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


210

我认为我误解了@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我猜是)?

Answers:


360

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

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

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


55
+1是我遇到过的mapdBy的最好和最简短的解释。
Ridcully

4
不过,最好在@OneToMany一侧使用CascadeType.ALL。
mvmn

48

请参阅此处以获取来自OpenJPA文档的示例。CascadeType.ALL表示它将执行所有操作。

引用:

CascadeType.PERSIST:保留实体时,还保留保留在其字段中的实体。我们建议自由应用此级联规则,因为如果EntityManager在刷新期间找到引用新实体的字段,并且该字段未使用CascadeType.PERSIST,则是错误的。

CascadeType.REMOVE:删除实体时,它也会同时删除此字段中保存的实体。

CascadeType.REFRESH:刷新实体时,还刷新此字段中保存的实体。

CascadeType.MERGE:合并实体状态时,还要合并此字段中保存的实体。

塞巴斯蒂安


4
JPA中的新增功能,此信息很有用,但是此处的Detach呢?
萨尔茨(Sarz)2014年

1
在CascadeType.DETACH中,分离实体时,em也会分离父实体持有的实体。
多里安·梅杰

29

正如我在本文和我的书《高性能Java持久性》中所解释的那样,您不应该使用CascadeType.ALL@ManyToOne因为实体状态转换应该从父实体传播到子实体,而不是相反。

@ManyToOne面始终是Child关联,因为它映射了基础的Foreign Key列。

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


18

根据EJB3.0规范

级联注释元素的使用可以用于将操作的效果传播到关联的实体。级联功能最常用于父子关系中。

如果X是一个受管实体,则删除操作会使它被删除。如果从X到这些其他实体的关系使用cascade = REMOVE或cascade = ALL标注元素值标注,则移除操作将层叠到X引用的实体。

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

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


11

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

之间更多的解释orphanRemoval=trueCascadeType.REMOVE在这里


4

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

@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;
}

这样,您就不必担心在批注中使用提取。但是请记住,删除用户时,您还将删除与用户对象连接的地址。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.