progonkpa
progonkpa

Reputation: 3940

JPA 2.1 hibernate one-to-many contraint violation duplicate entry

This code persists a Company entity that has a HashSet of Activity.

em.getTransaction().begin();

// De Morgen.
MediaGroup mediaGroupDM = new MediaGroup("De Persgroep", "Christian van Thillo", "Van Thillo Family");
HashSet<Activity> activities = new HashSet<>();
activities.add(new Activity("News paper"));
activities.add(new Activity("News website"));
activities.add(new Activity("Facebook opinion"));
Company deMorgen = new Company("De Morgen", "http://www.demorgen.be/", mediaGroupDM, activities);
em.persist(deMorgen);

em.getTransaction().commit();

The result in the database is fine. A new table 'company_activities' is created with an id of the company and id's of activities as shown below.

Result in the DB

But when I add another company which has the same activities, this exceptions gets thrown: MySQLIntegrityConstraintViolationException: Duplicate entry '3' for key 'UK_9j7c1qdg3rnhjioqut33ki7pr'

I understand it doesn't want duplicates in the activities_id column but what I try to achieve is this:

Company_id | activities_id
-----------|--------------
1          | 3
1          | 4
1          | 5
2          | 3
2          | 4
2          | 5

The Company entity

@Entity
public class Company{
    @Id
    @GeneratedValue
    private long id;
    @Column(unique = true)
    private String name;
    private String frontPageUrl;
    private String domainUrl;
    @OneToOne(cascade = CascadeType.ALL)
    private MediaGroup mediaGroup;
    @OneToMany(cascade = CascadeType.ALL)
    private Set<Activity> activities = new HashSet<>(0);

The Activity entity

@Entity
public class Activity {
    @Id
    @GeneratedValue
    private long id;
    @Column(unique = true)
    private String name;
    private String description;

I tried quite some configurations with the annotations. I also fetched the activities from the database and added them to the properties of the new company but no luck.

Test code Main:

public class Main {

    public Main() {
    }

    public static void main(String[] args) {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("MediaObserver");
        EntityManager em = emf.createEntityManager();

        Seed.companies(em);

        //emf.close();
    }
}

Test code Seed:

public class Seed {

    public static void companies(EntityManager em) {
        init(em);
        //reuseActivities(em);
    }

    private static void reuseActivities(EntityManager em) {
        em.getTransaction().begin();

        Company standaard = selectCompanyByName(em, "De Standaard");
        Activity facebook = selectActivityByName(em, "Facebook opinion");
        Activity newsWebsite = selectActivityByName(em, "News website");
        standaard.getActivities().add(facebook);
        standaard.getActivities().add(newsWebsite);
        em.persist(standaard);

        em.getTransaction().commit();
    }

    private static void init(EntityManager em) {
        em.getTransaction().begin();

        // De Morgen.
        MediaGroup mediaGroupDM = new MediaGroup("De Persgroep", "Christian van Thillo", "Van Thillo Family");
        HashSet<Activity> activities = new HashSet<>();
        activities.add(new Activity("News paper"));
        activities.add(new Activity("News website"));
        activities.add(new Activity("Facebook opinion"));
        Company deMorgen = new Company("De Morgen", "http://www.demorgen.be/", mediaGroupDM, activities);
        em.persist(deMorgen);

        // Standaard.
        MediaGroup mediaGroupDS = new MediaGroup("Mediahuis", "Gert Ysebaert", "");
        Company standaard = new Company("De Standaard", "http://www.standaard.be/", mediaGroupDS);
        em.persist(standaard);

        em.getTransaction().commit();
    }

    private static Company selectCompanyByName(EntityManager em, String companyName) {
        Query query = em.createQuery("SELECT c FROM Company c " +
                "WHERE c.name = :name");
        query.setParameter("name", companyName);

        return (Company) query.getSingleResult();
    }

    private static Activity selectActivityByName(EntityManager em, String activityName) {
        Query query = em.createQuery("SELECT a FROM Activity a " +
                "WHERE a.name = :name");
        query.setParameter("name", activityName);

        try {
            return (Activity) query.getSingleResult();
        } catch (NoResultException e) {
            System.out.println(activityName + " not found");
            return null;
        }
    }
}

Upvotes: 0

Views: 1055

Answers (1)

veljkost
veljkost

Reputation: 1932

What you have here is a Many-to-many relationship, not a @OneToMany as you stated in your Company entity. Try to define it as:

@ManyToMany(cascade = CascadeType.ALL)
@JoinTable(name = "company_activity", 
    joinColumns = {@JoinColumn(name = "company_id")},
    inverseJoinColumns = {@JoinColumn(name = "activity_id")})
private Set<Activity> activities = new HashSet<>(0);

Upvotes: 2

Related Questions