成为关系所有者的意义是什么?CASCADE 如何与 JPA 中的两侧一起工作?

What is the significance of being the realtionship owner and how does CASCADE work with the two sides in JPA?

我有两张桌子。交易和错误。事务和错误之间存在一对多关系。这是一个双向关系,Errors 是拥有方,因为在 Errors class 中指定了 @JoinColumn。我想了解 "OWN" 这种关系到底意味着什么。说现在我有,

场景一: 现在假设我们执行下面的代码。

transactions.setProcessed("Y");
errors.setActive(0);
transactions.setErrors(errors);
entityManager.merge(transactions);

我知道 TRANSACTIONS 中的 PROCESSED 字段将设置为 "Y",但 ERRORS 中的 ACTIVE 字段是否也会设置为 0 或不设置为 transactions IS NOT OWNING side of the relationship?

场景二: 另一方面,如果我们执行以下:

errors.setActive(0);
transactions.setProcessed("Y");
errors.setTransactions(transactions);
entityManager.merge(errors);

我知道 ERRORS 中的 ACTIVE 字段将被设置为 0,但是 TRANSACTIONS 中的 PROCESSED 字段是否也会设置为 "Y",因为 ERRORS 是关系的 OWNING 方?

JPA 级联类型如何与这样的场景相关联?

当我们说错误是拥有方时,这意味着关系的外键位于错误 table 中(您正在通过 @JoinColumn 执行此操作)。因此,关系的拥有方是将出现另一个实体的引用列的一方。 您可以通过在交易实体中指定 @OneToMany 来定义关系的反面。

现在是关于交易和错误更新问题的第二部分。在我看来,您可以通过应用适当的级联模式(持久化、删除等)来更新与事务关联的列表,这意味着您可以在事务实体 @OneToMany(cascade=CASCADETYPE.MERGE) 中指定,同时指定反向关系。这样,如果每当你要更新一个交易行,相应的错误行也可以更新。

但是,我认为以其他方式级联不是一个好的做法,即如果您更新子实体,父实体也应该更新,因为它可能导致许多数据不一致

在非双向关系中,您定义一个映射。当您对该映射进行更改时,很明显会发生什么——外键将得到更新。因为只有一个映射,所以不会有冲突(许多 JPA 提供程序如果检测到您对一个字段有多个 writable 映射,就会抛出错误)。

对于双向关系,这种控制不太明显。在您的事务-错误双向关系中,假设它是一个一对一双向映射,并且 Transaction1 设置为指向 Error1,反之亦然。假设您的应用程序确定 Transaction1 应该改为指向 Error2,并更改引用。如果 Error1 对 Transaction1 的引用没有更正以反映这种情况,那么 JPA 在确定将什么值放入外键时就会出现问题。这就是所有权发挥作用的地方。拥有方被认为是可写映射,对其的更改控制外键字段。在 OneToMany 中,拥有方通常是 ManyToOne 反向引用,因为它更自然,因为外键无论如何都在 table 中持有 ManyToOne。如果您进行更改以将错误添加到事务但不更改错误以也引用该事务,您的对象模型将与进入数据库的内容不同步 - 错误中的外键不会更改,但事务对象将在其列表中显示错误,直到它被刷新或从数据库中重新加载。

级联与所有权无关。它仅表示操作(保留、合并、删除、刷新)适用于关系引用的实体。如果使用 cascade.all 调用 em.refresh(transaction),事务和所有引用的错误将从数据库中刷新。 Error 具有的任何具有 ALL 或 REFRESH 级联设置的关系也将被刷新,依此类推。如果您将引用的事务实例放在后向引用上,JPA 应该检测到它已经刷新了引用的事务实例,但为什么要冒险呢。通常,级联选项只应放在需要它们以避免意外后果的映射上。如果您不确定是否需要它,请将其关闭,直到您确定为止。当有人去到处放置级联刷新时,诸如延迟获取和其他优化之类的事情可能会导致各种奇怪且难以发现的错误。

在您的示例中,您可以对应用程序将传递的根实体进行级联合并。对该图所做的任何更改都可以通过单个合并调用轻松获取,而无需在每个单独的叶子上调用合并。尽管您的模型的构建和序列化方式会影响合并,因此通常仅将级联选项放在根 -> 叶关系上,以避免出现根 -> 叶 -> 根' where root != root' 的问题。如果两边都有级联合并,root' 的状态可能会覆盖你在 root 中的更改。