ChatGPT解决这个技术问题 Extra ChatGPT

@ManyToOne JPA 关联的 CascadeType.ALL 是什么意思

我想我误解了 @ManyToOne 关系上下文中级联的含义。

案子:

public class User {

   @OneToMany(fetch = FetchType.EAGER)
   protected Set<Address> userAddresses;

}

public class Address {

   @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
   protected User addressOwner;

}

cascade = CascadeType.ALL 的含义是什么?例如,如果我从数据库中删除某个地址,我添加 cascade = CascadeType.ALL 的事实如何影响我的数据(我猜是 User)?


k
kostja

CascadeType.ALL 的含义是持久性会将所有 EntityManager 操作 (PERSIST, REMOVE, REFRESH, MERGE, DETACH) 传播(级联)到相关实体。

在您的情况下,这似乎是一个坏主意,因为删除 Address 会导致删除相关的 User。由于用户可以拥有多个地址,因此其他地址将成为孤立地址。然而,相反的情况(注释 User)将是有意义的 - 如果地址仅属于单个用户,则在删除该用户时传播属于该用户的所有地址的删除是安全的。

顺便说一句:您可能希望向您的 User 添加一个 mappedBy="addressOwner" 属性,以向持久性提供程序发出连接列应该在 ADDRESS 表中的信号。


不过,在 @OneToMany 方面拥有 CascadeType.ALL 可能会很好。
V
Vlad Mihalcea

您不应该在 @ManyToOne 上使用 CascadeType.ALL,因为实体状态转换应该从父实体传播到子实体,而不是相反。

@ManyToOne 端始终是子关联,因为它映射基础外键列。

因此,您应该将 CascadeType.ALL@ManyToOne 关联移动到 @OneToMany 端,这也应该使用 mappedBy 属性,因为它是最有效的一对多表关系映射。


谢谢弗拉德,我不确定为什么这不是最重要的答案。
C
Community

See here 获取 OpenJPA 文档中的示例。 CascadeType.ALL 表示它将执行所有操作。

引用:

CascadeType.PERSIST:当持久化一个实体时,也持久化其字段中持有的实体。我们建议自由应用此级联规则,因为如果 EntityManager 在刷新期间发现一个引用新实体的字段,并且该字段不使用 CascadeType.PERSIST,则这是一个错误。 CascadeType.REMOVE:删除实体时,也会删除该字段中持有的实体。 CascadeType.REFRESH:刷新实体时,也刷新该字段中持有的实体。 CascadeType.MERGE:合并实体状态时,也合并该字段中持有的实体。

塞巴斯蒂安


JPA 中的新功能,这些信息很有用,但是这里的 Detach 呢?
在 CascadeType.DETACH 中,分离实体时,也会分离父实体持有的实体。
C
Community

From the EJB3.0 Specification

级联注释元素的使用可用于将操作的效果传播到关联实体。级联功能最常用于父子关系。如果 X 是受管实体,则移除操作会导致它被移除。如果从 X 到这些其他实体的关系使用 cascade=REMOVE 或 cascade=ALL 注释元素值进行注释,则删除操作将级联到 X 引用的实体。

因此,简而言之,使用 CascadeType.All 定义的实体关系将确保父级上发生的所有持久性事件(例如持久化、刷新、合并和删除)都将传递给子级。定义其他 CascadeType 选项为开发人员提供了对实体关联如何处理持久性的更细粒度的控制。

例如,如果我有一个包含页面列表的对象 Book,并且我在此列表中添加了一个页面对象。如果定义 Book 和 Page 之间关联的 @OneToMany 注释标记为 CascadeType.All,则持久化 Book 会导致页面也持久化到数据库中。


l
lehins

在 JPA 2.0 中,如果您想删除从用户实体中删除的地址,您可以将 orphanRemoval=true(而不是 CascadeType.REMOVE)添加到 @OneToMany

orphanRemoval=trueCascadeType.REMOVE 之间的更多解释是 here


N
Negar Zamiri

如果您只想删除分配给用户的地址而不影响用户实体类,您应该尝试以下操作:

@Entity
public class User {
   @OneToMany(mappedBy = "addressOwner", cascade = CascadeType.ALL)
   protected Set<Address> userAddresses = new HashSet<>();
}

@Entity 
public class Addresses {
   @ManyToOne(cascade = CascadeType.REFRESH) @JoinColumn(name = "user_id")
   protected User addressOwner;
}

这样你就不用担心在注解中使用 fetch 了。但请记住,在删除用户时,您还将删除连接到用户对象的地址。