Hibernate: сравнение текущей и предыдущей записи - PullRequest
3 голосов
/ 08 октября 2008

Я хочу сравнить текущее значение находящегося в памяти объекта Hibernate со значением в базе данных:

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);    

В CODEBLOCK # 1 Я получаю это newEntity.getProperty()="new value" И oldEntity.getProperty()="new value" (хотя я ожидал oldEntity.getProperty()="old value", конечно). На самом деле эти два объекта абсолютно одинаковы в памяти.

Я запутался с HibernateSessionFactory.getSession().evict(newEntity) и попытался установить oldEntity=null, чтобы избавиться от него (мне это нужно только для сравнения):

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);

и теперь эти две сущности различны, но, конечно, я получаю страшную org.hibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session.

Есть идеи?

РЕДАКТИРОВАТЬ: Я попробовал стратегию двойной сессии; Я изменил свой HibernateSessionFactory, чтобы реализовать карту сеанса, а затем ...

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);

Мой модульный тест зависает при попытке распечатать заметку oldEntity ...: - (

Ответы [ 2 ]

6 голосов
/ 09 октября 2008

Два простых варианта приходят на ум:

  1. Извлеките oldEntity перед сохранением newEntity
  2. Используйте метод session.merge () для oldEntity, чтобы заменить версию в кэше сеанса (newEntity) на исходную (oldEntity)

РЕДАКТИРОВАТЬ : чтобы уточнить, проблема здесь в том, что Hibernate поддерживает постоянный контекст, то есть объекты, которые отслеживаются как часть каждого сеанса. Вы не можете выполнить update () для отдельного объекта (который не находится в контексте), пока в контексте есть прикрепленный объект. Это должно работать:

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

и так должно это:

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
0 голосов
/ 08 октября 2008

А как насчет использования session.isDirty ()? JavaDoc говорит, что метод ответит на вопрос «Будет ли выполнен какой-либо SQL, если мы сбросим этот сеанс?» Конечно, это сработало бы, только если у вас была новая чистая сессия для начала. Другой вариант - просто использовать две разные сессии.

...