Hibernate: comparing current & previous record

diff, hibernate, jpa, session

Solution

Two easy options spring to mind:

- Evict oldEntity before saving newEntity

- Use session.merge() on oldEntity to replace the version in the session cache (newEntity) with the original (oldEntity)

EDIT: to elaborate a little, the problem here is that Hibernate keeps a persistence context, which is the objects being monitored as part of each session. You can't do update() on a detached object (one not in the context) while there's an attached object in the context. This should work:

HibernateSession sess = ...;
MyEntity oldEntity = (MyEntity) sess.load(...);
sess.evict(oldEntity); // old is now not in the session's persistence context
MyEntity newEntity = (MyEntity) sess.load(...); // new is the only one in the context now
newEntity.setProperty("new value");
// Evaluate differences
sess.update(newEntity); // saving the one that's in the context anyway = fine

and so should this:

HibernateSession sess = ...;
MyEntity newEntity = (MyEntity) sess.load(...);
newEntity.setProperty("new value");
sess.evict(newEntity); // otherwise load() will return the same object again from the context
MyEntity oldEntity = (MyEntity) sess.load(...); // fresh copy into the context
sess.merge(newEntity); // replaces old in the context with this one

Problem

I want to compare the current value of an in-memory Hibernate entity with the value in the database: ``` HibernateSession sess = HibernateSessionFactory.getSession(); MyEntity newEntity = (MyEntity)sess.load(MyEntity.class, id); newEntity.setProperty("new value"); MyEntity oldEntity = (MyEntity)sess.load(MyEntity.class, id); // CODEBLOCK#1 evaluate differences between newEntity and oldEntity sess.update(newEntity); ``` In CODEBLOCK#1 I get that `newEntity.getProperty()="new value"` AND `oldEntity.getProperty()="new value"` (while I expected `oldEntity.getProperty()="old value"`, of course). In fact the two objects are exactly the same in memory. I messed around with `HibernateSessionFactory.getSession().evict(newEntity)` and attempted to set `oldEntity=null` to get rid of it (I need it only for the comparison): ``` HibernateSession sess = HibernateSessionFactory.getSession(); MyEntity newEntity = (MyEntity)sess.load(MyEntity.class, id); newEntity.setProperty("new value"); HibernateSessionFactory.getSession().evict(newEntity); MyEntity oldEntity = (MyEntity)sess.load(MyEntity.class, id); // CODEBLOCK#1 evaluate differences between newEntity and oldEntity oldEntity = null; sess.update(newEntity); ``` and now the two entities are distinct, but of course I get the dreaded `org.hibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session`. Any idea? EDIT: I tried the double session strategy; I modified my `HibernateSessionFactory` to implement a map of session and then... ``` Session session1 = HibernateSessionFactory.getSession(SessionKeys.DEFAULT); Session session2 = HibernateSessionFactory.getSession(SessionKeys.ALTERNATE); Entity newEntity = (Entity)entity; newEntity.setNote("edited note"); Entity oldEntity = (Entity)session1.load(Entity.class, id); System.out.println("NEW:" + newEntity.getNote()); System.out.println("OLD: " + oldEntity.getNote()); // HANGS HERE!!! HibernateSessionFactory.closeSession(SessionKeys.ALTERNATE); ``` My unit test hangs while attempting to print the oldEntity note... :-(

Original source