10

我有一组相互连接形成循环的实体,即父实体 P 与两个子实体 C1 和 C2 具有两个一对多关系,并且每个实体与另一个实体具有一对多关系A. 实体 A 实现了这些实体(C1,C2)的关联,并定义了关系的属性(它不仅仅是一个连接表)。所有的关系都可以双向导航。
领域对象
这个设计产生了以下问题:考虑到您总是在根实体 P 上调用实体管理器操作,应该采用什么级联策略才能使实体 A 可以持久化/合并?A 应该可以从两条路径级联到达吗?

注意事项:似乎如果应用程序选择只提供一个级联路径,则可能存在引发 TransientObjectException 的场景。如果它提供了两条路径,那么这些路径必须完成整个循环,例如可以尝试通过 A 保存 C1。

版本:JPA 2.0、Hibernate 核心 4.1.7、hibernate-jpa-2.0-api 1.0.1

4

2 回答 2

3

我可以给你我的 2 美分,对不起,如果我的回答有点长。

如果您有这种级联冲突,可能是因为您的级联方法或域模型没有很好地定义。我会小心地将级联策略推广到整个图或一组不相关的元素。

我的建议是,级联策略应该只应用于紧密联系在一起的数据集,并且是相同类型的,比如 java 世界中的类及其(私有)内部类。母类与其子类之间的关系也应该是排他的(在 UML 中称为非共享关联)。

当然,您可以不这样做(我们都可以是懒惰的),但最终您可能会在单个持久性流(或持久性配置)和业务流之间创建一个耦合网络。您将不得不管理大量异常,并围绕您之前放置的级联策略(保存、更新、删除)执行大量配置逻辑。

极端的方法是有些人可能只想保存一个大根对象。为什么不?其余的“应该继续级联”。但事实上,这可能会严重限制系统的可维护性。此外,在加载、保存和合并大图时,您可能必须管理大图在内存中的状态。

如果您使用 Web 应用程序或任何客户端-服务器应用程序,您的 Web 工作流应该能够在每次请求时保存一组有限的对象,而不必保存根元素中的所有内容。我知道我没有直接回答你的问题。所以让我们回到你的例子:

假设 P 是一家银行,C1 和 C2 是两个客户,A 是一个产品。

我有两个简单的答案:1)每一层都可以单独保存而无需任何级联。但它可以在同一个事务中完成,如果你愿意,也可以在同一个 DAO 中完成。

2)P和C“可以”级联。但是 A 必须保存在不同的工作流程中。

这让我想起了 Peter Coad 的一章,他谈到了“领域驱动分析”:http ://www.petercoad.com/download/bookpdfs/jmcuch01.pdf

本章解释了如何在不同的原型中分离图中的不同对象。事务数据和描述或“事物”之间的持久性工作流不应该相同。这有助于制定更好的级联策略:

 The four archetypes of Peter Coad are:
 - Is it a moment or interval? 
 - Is it a role played? 
 - Is it a catalog-entry-like description? 
 - Otherwise, it's a party, place, or thing.

我希望它有所帮助。

于 2012-11-29T18:56:49.150 回答
3

通常一个好主意是仅在紧密关联中级联,并且仅在父->子(或所有者->拥有)方向。在您的情况下,它可能是P->C1and P->C2。由于A没有一个明显的父级,因此应单独保存。这可以像 @etienno 在你的 DAO 中提到的那样在单个事务中与P(and C1, C2) 一起完成。我不知道您的域模型,但甚至可能A在概念级别上是一个单独的实体,在这种情况下,单独保存更加合理。

从长远来看,级联到许多不密切相关的对象可能会使整个图在变大时变得难以管理。

在这种情况下,最好问“没有 Hibernate 你会怎么做”这个问题。在您的情况下,您可能会首先保存P,然后C1C2然后A。AFAIK JPA/Hibernate 没有提供任何明确的方式来强制执行这种顺序,所以有些事情必须由您手动完成。

于 2012-12-04T12:01:57.047 回答