Reputation:
I have a main thread where I get an object from database, then close the EntityManager, then put the object into a queue. A worker thread makes some business with the object, then puts it into a finished queue. Then the main thread gets the object from the finished queue and merges the object:
EntityManager em = entityManagerFactory.createEntityManager();
em.getTransaction().begin();
// Print the primary key ID of the object,
// it is NOT empty yes it exists in the db.
em.merge(myObject);
em.getTransaction().commit();
em.close();
I confirm the primary key ID of the object by printing it before merging, and yes it exists in the database. Unfortunately it throws a duplicate key exception from MySQL. How? Shouldn't JPA know that the object has an ID and update it, instead of inserting?
The SQL statement that is mentioned in the exception is an INSERT
statement, not UPDATE
.
The primary key of the entity is below:
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "COMPANYID")
private long companyId;
I was setting a List field of the object to the List field of another newly created object. Then, for some reason that I don't understand, EclipseLink thinks that the object is a new object. God knows why. This JPA stuff is extremely counter-intuitive. You have to be truly an expert to use it. Otherwise it is totally useless because anytime you can mess it up. In practice the total headache and time loss it creates is much more than its advantages!
Anyway, I solved the problem by adding the elements of the other object to the old object as follows:
oldObject.getHistories().clear();
for (History history : newObject.getHistories()) {
history.setCompany(oldObject);
oldObject.getHistories().add(history);
}
Now EclipseLink correctly UPDATES instead of inserting new. I will be happy if someone can explain why this behavior?
Upvotes: 14
Views: 8590
Reputation: 1289
This is happening because your EntityManager does not know about the object myObject.
For your code to work you should do something like this:
EntityManager em = entityManagerFactory.createEntityManager();
em.getTransaction().begin();
Object myObject = em.findById(someId);
em.getTransaction().commit();
object.setName("yourNewName");
.....................
//And now run
em.getTransaction().begin();
em.merge(myObject);
em.getTransaction().commit();
em.close();
Please note that I close the EntityManager only after I have done all my transactions needed to the database. And myObject is exactly the one that I recieved from my em.findById, I do not simply create a new object, because that will not work.
This is a tutorial that maybe can help you understand a bit more.(you have in the right a playlist with more videos about JPA ).
Upvotes: 2