Hibernate:比较当前和&之前的纪录

时间:2008-10-08 14:18:44

标签: hibernate diff session

我想比较内存中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 个答案:

答案 0 :(得分:6)

我想到了两个简单的选择:

  1. 在保存newEntity之前逐出oldEntity
  2. 在oldEntity上使用session.merge()将会话缓存中的版本(newEntity)替换为原始(oldEntity)
  3. 编辑:详细说明一下,这里的问题是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
    

答案 1 :(得分:0)

使用session.isDirty()怎么样? JavaDoc说该方法将回答“如果我们刷新此会话,是否会执行任何SQL?”当然,这只有在您开始使用新的干净会话时才有效。另一个选择 - 只使用两个不同的会话。