Reputation: 4275
(This is a simplification of the real problem)
Let's start with the following little class:
@Entity
class Test {
Test(int id, String name) {
this.id = id;
this.name = name;
}
@Id
private int id;
@Column
private String name;
@Override
public int hashCode() {
return id;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof Test) {
return id == ((Test) obj).id;
}
return false;
}
}
If we execute the following, no exception occurs:
EntityManagerFactory factory = Persistence.createEntityManagerFactory("local_h2_persistence");
EntityManager theManager = factory.createEntityManager();
EntityTransaction t = theManager.getTransaction();
Test obj1 = new Test(1, "uno");
tA.begin();
AtheManager.persist(obj1);
AtheManager.persist(obj1); // <-- No exception
tA.commit();
I guess the second call is ignored, or maybe the object is saved to the DB again. The thing is there is no problem in saving the same entity twice. Now let's try the following:
EntityManagerFactory factory = Persistence.createEntityManagerFactory("local_h2_persistence");
EntityManager theManager = factory.createEntityManager();
EntityTransaction t = theManager.getTransaction();
Test obj1 = new Test(1, "uno");
Test obj1_ = new Test(1, "uno");
tA.begin();
AtheManager.persist(obj1);
AtheManager.persist(obj1_); // <-- javax.persistence.EntityExistsException: a different object with the same identifier value was already associated with the session
tA.commit();
What? How could it possibly be relevant that the object is in a different memory location? Somehow it is and the code throws an exception.
How can I make the second example work just like the first?
Upvotes: 1
Views: 2720
Reputation: 4275
I am just rewriting what @jb-nizet wrote in the comments, which feels like the answer to me:
Hibernate doesn't use ==. It simply does what you're telling it to do. persist's contract is: associate this object with the session. If it's already associated to the session, it's a noop. If it isn't, it is associated to the session to be inserted in the database later. If what yo want to do is make sure the state of this object is copied to a persistent entity, and give me back that persistent entity, then you're looking for merge().
So the solution was to just use
AtheManager.merge(obj1);
instead of
AtheManager.persist(obj1);
Upvotes: 1
Reputation: 509
In the first example you pass a reference to an object to save it and in the second call you pass exactly the same reference; they both point to the same object in memory.
However, in the second example you allocated two objects with two new calls which creates the objects at two different memory addresses; they are two different objects. The first reference points to some other memory address then the second object's reference. If you tried this in the second example it would return false: obj1 == obj1_
Upvotes: 0
Reputation: 1590
In first case, you save the same object twice, which is allowed. But in second case, you save two different object to database, but both has the same primary key. It is database constraint violation.
Upvotes: 0