EclipseLink Creates Duplicate Records in a One-to-Many Relationship

I am using EclipseLink 2.4.1 and JPA 2.0. In my example, I have the following class definitions:

@Entity public class Shepard { @Id @GeneratedValue(strategy=GenerationType.IDENTITY) @Column(name = "id") private Long id; @OneToMany(mappedBy = "shepard", cascade = CascadeType.ALL, fetch = FetchType.LAZY) private List<Sheep> sheeps; public void addSheep(Sheep sheep) { if (sheep != null) { if (sheeps == null) { sheeps = new ArrayList<>(); } if (!sheeps.contains(sheep)) { sheeps.add(sheep); } } } } @Entity public class Sheep { @Id @GeneratedValue(strategy=GenerationType.IDENTITY) @Column(name = "id") private Long id; @Column(name = "name") private String name; @ManyToOne(fetch = FetchType.EAGER, optional = false) @JoinColumn(name="shepard_id") private Shepard shepard; public Sheep(Shepard shepard, String name) { this.shepard = shepard; this.name = name; shepard.addSheep(this); } } 

Now when I write the Junit test and do the following. Note that the Sheep constructor calls Shepard.addSheep (Sheep)!

 EntityManagerFactory emf = Persistence.createEntityManagerFactory("data"); EnttyManager em = emf.createEntityManager(); Shepard shepard = new Shepard(); // I Persist Shepard em.getTransaction().begin(); em.persist(shepard); em.getTransaction().commit(); // II Persist Tilda Sheep tilda = new Sheep(shepard, "Tilda"); em.getTransaction().begin(); em.persist(tilda); em.getTransaction().commit(); // III Persist Martha via Shepard Sheep martha = new Sheep(shepard, "Martha"); em.getTransaction().begin(); em.merge(shepard); em.getTransaction().commit(); 

And then do a named query for Sheep's, I get a duplicate entry for "Tilda"!

This does not happen when I code

 em.persist(martha); 

as the last entity manager access.

Analyzing the debug output, I see that after II there is one Shepard object with [id = 1] and one Sheep object with [id = 1]. Before and after III, Shepard contains two sheep references, earlier with [id = 1 ] for Tilda and [id = null] for Martha. After III, Shepard contains two references of Sheep with [id = 2 ] for Tilda and [id = 3] for Martha.

From the debug output of EclipseLink, I see that III outputs two inserts into the Sheep table. In the database, three Lamb records end with the identifier above.

Next, I get the following error:

 [EL Warning]: 2013-06-21 09:53:26.631--UnitOfWork(221387686)--Thread(Thread[main,5,main])--Exception [EclipseLink-7251] (Eclipse Persistence Services - 2.4.1.v20121003-ad44345): org.eclipse.persistence.exceptions.ValidationException Exception Description: The attribute [id] of class [Sheep] is mapped to a primary key column in the database. Updates are not allowed. 

Is this an EclipseLink error? Or what am I doing wrong here?

+4
source share
2 answers

In the sheep class, you have a โ€œforeign keyโ€ for the Sheppard class, which is not part of the primary key.

Try creating an Id class to use a compass key in a sheep class.

 @Id @ManyToOne(fetch = FetchType.EAGER, optional = false) @JoinColumn(name="shepard_id") private Shepard shepard; 
+2
source

You do not need to call merge () since shepard is already a managed entity. Merging is for single / serialized objects, not for managed objects. If you have a cascade persisting on Ove, then you do not need to do anything, just call the commit.

However, calling the merge () function should not cause any problems, so this is very strange. If you can recreate the problem in a test, report a bug. You can also try version 2.5 to make sure it is fixed.

I guess creating OneToMany EAGER might solve the problem. Also, if you create a new EntityManager for each transaction, then you will not have a problem (if you cause a merge in both cases).

+2
source

Source: https://habr.com/ru/post/1487317/


All Articles