Hibernate拦截器:在更新集合元素时拦截实体

时间:2009-10-14 18:38:37

标签: hibernate interceptor

我需要知道如何设置Hibernate(...)来实现以下问题:

我有一个双向(组合)一对多关联(a.bs是一个Set对象,b.a是一个A对象)。当我从DB加载“a”并更新其中一个“bs”时,我需要在saveOrUpdate A时使用Hiernate拦截实体。

代码:

public class A {
   Set<B> bs = new HashSet<B>();
   // ... other fields and setters/getters
}
public class B {
   A a = null;
   // ... other fields and setters/getters
}

用例:

A a = load("idA"); // load A from DB
B b = s.getBById("idB"); // get a B element of A
b.setName("blablabla"); // update a field of B
saveOrUpdate(a); // persist A entity with its Bs (including modified B)

执行更改是因为(迷你)模型已正确注释。

问题是我的拦截器只检测B实体的变化,但不检测A.我需要检测A变化,因为我需要更新审计信息。

其他观点是:我需要通过B获取A实体并更新它。事实上,我可以从B获得A,但这种变化并没有持续......

简化问题: 当我的拦截器拦截B实体时,我必须修改一个实体(设置一个日期)。它在onSave中工作,但在onFlushDirty中不工作。为什么?

这是: 当B被更新时,被拦截(onFlushDirty)。除了其他方面,onFlushDirty方法的主体执行此操作:

b.getA().setLastModifyDate(new Date());

所以,在那个时刻,附加到会话的实体应该变脏,因此它应该引发一个拦截动作......我的意思是,应该再次调用onFlushDirty方法,他是A实体的时间。我错了吗? 但是,无论如何,应该更新A.lastModifyDate ......而且这种情况不会发生!!!

下面我展示了我的应用程序的实际行为:

  1. 我创建了一个A对象
  2. 我创建了一个B对象,并将其与A
  3. 相关联
  4. 我坚持A =&gt; A.lastModifyDate是正确的日期(确定

  5. 我创建了一个A对象

  6. 我创建了一个B对象,并将其与A
  7. 相关联
  8. 我坚持A =&gt; A.lastModifyDate是正确的日期(确定
  9. 我加载B对象,我更新它并且我坚持B - &gt; A.lastModifyDate是正确的日期(确定

  10. 我创建了一个A对象

  11. 我创建了一个B对象,并将其与A
  12. 相关联
  13. 我坚持A =&gt; A.lastModifyDate是正确的日期(确定
  14. 我加载一个对象,我更新它的B对象,我坚持A - &gt; A.lastModifyDate 不是正确的日期( KO

  15. 我创建了一个A对象

  16. 我创建了一个B对象,并将其与A
  17. 相关联
  18. 我坚持A =&gt; A.lastModifyDate是正确的日期(确定
  19. 我加载一个对象,我更新任何A的字段以及它的B对象,我坚持A - &gt; A.lastModifyDate 不是正确的日期( KO

  20. 我创建了一个A对象并且我坚持了它。

  21. 我加载了一个对象,我将它与一个新的B对象关联,并且我坚持A =&gt; A.lastModifyDate是正确的日期(确定

  22. 我创建了一个A对象并且我坚持了它。

  23. 我加载了一个对象,我更新了任何A的字段,我将它与一个新的B对象相关联,并且我坚持A =&gt; A.lastModifyDate是正确的日期(确定
  24. 有什么想法吗?

    谢谢!

3 个答案:

答案 0 :(得分:3)

您必须使用onCollectionUpdate来解决问题

答案 1 :(得分:1)

好的,如果(正如你在评论中所说的那样)你使用的是实际Interceptor,那么我不太清楚你的意思是“只检测B中的变化,而不是A”。由Itceptor的 实现来检测您想要检测的内容。

按照上面的例子,当你调用session.saveOrUpdate(a)时,你的拦截器的onSave()方法将被调用A和B(假设适当的级联设置可能是因为你说b是被救了)当然,这假设A实际上已被修改(因此被发现是脏的)。除非未将关联声明为反向,否则修改B 单独不会使A变脏。在这种情况下,您可以执行在为B调用onSave()时需要执行的操作,或者您可以挂钩findDirty()方法,该方法将针对当前在会话中的所有实体进行调用。但请注意,它可能不止一次被调用 - 基本上是在每次刷新而不是saveOrUpdate()上。

答案 2 :(得分:0)

如果你想使用onFlushDirty使它工作,你必须在saveOrUpdate(a)之后手动刷新会话;这将确保持久对象中的任何更新都将进入db commit;如果你的自动刷新模式,提交将触发另一个刷新,这将发现父实体为脏。否则对象不会保存becoz拦截器只会保存当前修改过的实体。

我有一个类似的情况,我需要从子集合更新父实体的审计字段。区别在于我的服务只保存除父母实体之外的子集合列表。