2013-08-01 2 views
2

Я работаю с OpenJPA 2.2.1, и хотел бы сделать следующее:Howto сравнить два объекта в JPA onPreUpdate

1) Загрузите объект 2) Изменить объект 3) Проверьте изменения, сделанные перед сохранением сущность

Что я сделал:

1) Загрузите объект через

EntityManager.find(MyObject.class, id); 

2) Хорошо, довольно ясно, я-я чернила, что-то вроде

MyObject obj = EntityManager.find(MyObject.class, id); 
    obj.setName("New name"); 

3) пыталось выселить объект из PersistenceContext и загрузить его снова из базы данных с помощью:

EntityManager.evict(MyObject.class, id); 
    EntityManager.find(MyObject.class, id); 

Объекта, возвращаемый вызова находки() в 3) всегда равный (равный ID) субъекту, найденному в 1)

Я думал, что могу удалить объект из PersistenceContext/cache путем выселения.

Как я могу добиться, чтобы иметь два различных сущностей: а) измененное лицо и б) оригинал объект из базы данных, загруженная в шаге 3)

А: Если я обновить() предприятие я ожидаю метод find, чтобы вернуть обновленный. Это верно?

Я тоже попробовал @PreUpdate слушатель с тем же результатом, так что я думаю, что должна быть что-то я не понял, о JPA PersistenceContext или Java ссылки ...

Я надеюсь, что я предоставил достаточно информацию! Заранее спасибо!

+0

С «равным идентификатором» вы имеете в виду, что оба экземпляра «MyObject» имеют одинаковое значение «id»? Потому что это именно то, что вы попросили entityManager для ... – mabi

ответ

3

Хороший обзор жизненного цикла JPA я нашел этот сайт (в частности, диаграмма состояний), чтобы быть полезным: http://www.objectdb.com/java/jpa/persistence/managed

Основной вынос в том, что объекты не «исчезают», когда вы удалите их из контекст персистентности.Ваш obj по-прежнему будет указывать на полностью инициализированный MyObject с name, установленным на «Новое имя». Единственное различие заключается в том, что фиксация транзакции/очистка контекста персистентности больше не будет обновлять соответствующую запись в базе данных.

У вас есть несколько вариантов, если вы хотите посмотреть изменения на obj перед тем, как зайти в базу данных. Если быстро и грязно хватает, я бы предложил

MyObject original = obj.clone(); 

и сравнить obj и original с любым инструментом (или просто печать как в журнале) вам нравится.

Что касается refresh(), посмотрите на то, что this page говорит:

Содержание управляемого объекта в памяти отбрасывается (в том числе изменения, если таковые имеются) и заменены данными, извлеченными из базы данных. Это может быть полезно для обеспечения того, что приложение имеет дело с самой последней версией объекта сущности, на случай, если оно могло быть изменено другим EntityManager с момента его получения.

+0

Привет, mabi, большое спасибо за ваши объяснения. Просто я правильно понимаю: – 4thfloorstudios

+0

управляется -> изменения будут удалены, удалены -> объект будет удален при фиксации, отсоединен -> ничего не происходит при поступлении. Кажется, Cache.evict() работает только с кэшем L2, который я не использую, поэтому я попытался отсоединить его, который тоже не работал. Я видел здесь [link] (http://tomee.apache.org/jpa-concepts.html), что средство отсоединения для удаления объекта из PersistenceContext, поэтому мне интересно, почему find() дает мне исходную ссылку и не делает перезагрузить объект из базы данных? – 4thfloorstudios

+0

Да, вы правы в управлении, удалении и отключении. Вы подтвердили, что это одна и та же * ссылка *, как в «самом экземпляре объекта»? Если да, попробуйте начать новый сеанс. У меня нет опыта работы с OpenJPA, но у Hibernate также есть кеш для каждого сеанса для извлечения сущностей. Во всяком случае, если вы клонируете/копируете-копируете копию своего объекта, вы можете просто продолжать без отсоединения и сравнить эти два раза, когда захотите. – mabi

0

Как насчет:

1/Read (или найти) объекта в памяти [который является то, что вы сделали]

2/Удалить объект из хранилища; что-то в соответствии с:

em.getTransaction().begin(); 
em.remove(obj); 
em.getTransaction().commit(); 

3/Выполняйте любые обновления на объекте в памяти;

obj.setName("My New Name"); 

4/Наконец сохраняется обновленный объект:

em.getTransaction().begin(); 
em.persist(obj); 
em.getTransaction().commit(); 

Вышеуказанные фрагменты основаны на javax.persistence.*; пакета и em является экземпляром определяется следующим образом:

EntityManagerFactory emFactory = Persistence.createEntityManagerFactory(PERSISTENT_UNIT); 
EntityManager em = emFactory.createEntityManager(); 

Все самое лучшее !

+0

Спасибо за ваш ответ, но я искал способ сравнить исходный и измененный объект. С вашего пути я удаляю оригинал и сохраняю измененный снова, поэтому я не могу сравнивать. – 4thfloorstudios

2

Если вы используете Spring @Transactional, как я. Вы можете сделать следующее:

@Transactional 
MyEntityObject update(MyEntityObject myEntityObject){ 
    boolean isNameChanged; 
    em.detach(myEntityObject); 
    MyEntityObject inDBObject = em.load(myEntityObject.getId()); 
    isNameChanged = (myEntityObject.getName() != inDBObject.getName()); 
} 
Смежные вопросы