【问题标题】:Hibernate interceptor: entity intercepted when a collection element updatedHibernate拦截器:当集合元素更新时拦截的实体
【发布时间】:2010-12-06 19:03:07
【问题描述】:

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

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

代码:

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 实体时,我必须修改 A 实体(设置日期)。它在 onSave 中可以正常工作,但在 onFlushDirty 中却不行。为什么?

这是: 当 B 被更新时,被拦截(onFlushDirty)。 onFlushDirty 方法的主体,除其他外,这样做:

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

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

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

  1. 我创建了一个 A 对象
  2. 我创建了一个 B 对象并将其关联到 A
  3. 我坚持 A => A.lastModifyDate 是正确的日期 (OK)

  4. 我创建了一个 A 对象

  5. 我创建了一个 B 对象并将其关联到 A
  6. 我坚持 A => A.lastModifyDate 是正确的日期 (OK)
  7. 我加载 B 对象,我更新它并坚持 B -> A.lastModifyDate 是正确的日期(OK

  8. 我创建了一个 A 对象

  9. 我创建了一个 B 对象并将其关联到 A
  10. 我坚持 A => A.lastModifyDate 是正确的日期 (OK)
  11. 我加载 A 对象,更新其 B 对象并坚持 A -> A.lastModifyDate 不是正确的日期 (KO)

  12. 我创建了一个 A 对象

  13. 我创建了一个 B 对象并将其关联到 A
  14. 我坚持 A => A.lastModifyDate 是正确的日期 (OK)
  15. 我加载 A 对象,更新任何 A 的字段及其 B 对象,并坚持 A -> A.lastModifyDate 不是正确的日期(KO)

  16. 我创建了一个 A 对象并将其持久化。

  17. 我加载了 A 对象,我将一个新的 B 对象关联到它,并且我坚持 A => A.lastModifyDate 是正确的日期 (OK)

  18. 我创建了一个 A 对象并将其持久化。

  19. 我加载 A 对象,我更新任何 A 的字段,我将一个新的 B 对象关联到它,我坚持 A => A.lastModifyDate 是正确的日期(OK

有什么想法吗?

谢谢!

【问题讨论】:

  • 你能澄清一下你所说的“拦截”是什么意思吗?真正的拦截器?事件监听器?级联行为?
  • 实际拦截器!我不使用监听器。

标签: hibernate interceptor


【解决方案1】:

你必须使用 onCollectionUpdate 来解决问题

【讨论】:

    【解决方案2】:

    好的,所以如果(如您在评论中所说)您使用的是实际的Interceptor,那么我不太确定您所说的“仅检测 B 的变化,而不是 A”的意思。由您的拦截器实现来检测您想要检测的任何内容。

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

    【讨论】:

      【解决方案3】:

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

      我有一个类似的情况,我需要从子集合中更新父实体的审计字段。不同之处在于我的服务仅保存不包括父实体的子集合列表。

      【讨论】:

        猜你喜欢
        • 2012-09-26
        • 2023-03-31
        • 1970-01-01
        • 2015-11-22
        • 2013-06-25
        • 2018-08-09
        • 2014-03-10
        • 2010-09-07
        • 1970-01-01
        相关资源
        最近更新 更多