The reason for this error is due to a change in the identity of the managed entity.
During the PersistenceContext life cycle, there can be one and only one managed instance of any object. You cannot change the existing managed entity identifier for this.
In your example, even if you are starting a new transaction, you should remember that PersistenContext was not closed, so you still have the c1 managed entity attached to the Hibernate session.
When you are trying to find a company:
c1 = em.find (Company.class, new Company.Identity("ACURA"));
The identifier does not match the identifier for the Company, which is attached to the current session, so a request is issued:
Hibernate: select company0_.name as name1_0_0_ from Company company0_ where company0_.name=?
Since SQL is CASE INSENSITIVE, you practically select the same database row as the current managed company (persistent c1 ).
But you can only have one managed entity for the same database row, so Hibernate will reuse the managed entity instance, but it will update the identifier to:
new Company.Identity("ACURA");
You can verify these assumptions with the following test:
String oldId = c1.name; Company c2 = em.find (Company.class, new Company.Identity("ACURA")); assertSame(c1, c2); assertFalse(oldId.equals(c2.name));
When the second transaction is completed, the flash will try to update the object identifier (which has changed from "Acura" to "ACURA"), and therefore DefaultFlushEntityEventListener.checkId () does not work.
According to JavaDoc, this check is intended for:
make (ing) sure () user did not distort identifier
To fix this, you need to remove this call to the search method:
c1 = em.find (Company.class, new Company.Identity("ACURA"));
You can check that c1 already connected:
assertTrue(em.contains(c1));