JPA + Hibernate - 实体关系中的循环 - 级联策略

时间:2012-11-29 08:59:03

标签: java hibernate jpa cascade

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

注意事项:似乎如果应用程序选择只提供一个级联路径,则可能会出现抛出TransientObjectException的情况。如果它提供两个路径,则这些路径必须进行完整循环,例如可以尝试通过A保存C1。

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

2 个答案:

答案 0 :(得分: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.

我希望它有所帮助。

答案 1 :(得分:3)

通常,一个好主意是仅在密切关联中进行级联,并且仅在 parent->子(或所有者 - >拥有)方向中进行级联。在您的情况下,它可能是P->C1P->C2。由于A没有一个明显的父级,因此应单独保存。这可以通过@etienno在您的DAO中在单个交易中与P(以及C1C2)一起提及。我不知道你的域模型,但是甚至A在概念层面上也是一个单独的实体,在这种情况下,单独的保存甚至更合理。

级联到许多不密切相关的对象可能会在长期内使整个图形变大,变得无法管理。

在这样的情况下,问一个问题“如果没有Hibernate你会怎么做”总是好的。在您的情况下,您可能先保存P,然后C1C2,然后A。 AFAIK JPA / Hibernate没有提供任何明确的方法来强制执行此类订单,因此有些事情必须由您手动完成。