Hibernate中的级联类型save update

10
我将使用带有JPA注释的Hibernate来进行关系映射。 我的代码中有三个实体:UserGroupUser_GroupUserGroup之间存在ManyToMany关系。 User_Group是一种桥接表,但具有一些附加字段。因此,这里是修改后的映射代码。
@Entity
@Table(name = "USERS")
public class User {

@OneToMany(mappedBy = "user")
private Set<UserGroup> userGroups
}

@Entity
@Table(name = "GROUPS")
public class Group {
@OneToMany(mappedBy = "group")
private Set<UserGroup> userGroups
}

用户组
@Entity
@Table(name = "USERS_GROUPS")
public class UserGroup {

@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "USER_ID")  
private User user;
@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "GROUP_ID")
private Group group;
}

当我将用户和组对象设置为用户组并保存时。
User user = new User("tommy", "ymmot", "tommy@gmail.com");
Group group = new Group("Coders");

UserGroup userGroup = new UserGroup();
userGroup.setGroup(group);
userGroup.setUser(user);
userGroup.setActivated(true);
userGroup.setRegisteredDate(new Date());

session.save(userGroup);

事情进展顺利。使用CascadeType.ALL,组对象和用户对象也会被更新。但是当我删除userGroup对象时,子对象也会被删除。

严格禁止删除子对象。

JPA中没有CascadeType.SAVE-UPDATE,它只保存或更新但不删除。我该如何实现这一点。

如果我从映射中删除CascadeType.ALL,子对象就不会得到更新,而我需要更新它们。

3个回答

17

SAVE_UPDATE 适用于 save()、update() 和 saveOrUpdate() 这三个 Hibernate 专有方法。JPA 只有 persist() 和 merge()。因此,如果要在 Hibernate 专有方法上使用级联,您需要使用 Hibernate 专有注释。在这种情况下,可以使用 Cascade

或者您可以停止使用 Hibernate Session,改用标准 JPA API。


摆脱Hibernate会话不是一个选项,而且在整个代码中我已经使用了JPA注释进行映射。因此,唯一的方法似乎是删除CASCADETYPE.ALL并明确更新子对象,发出另一个查询到数据库? - underdog
3
不是的。我的回答告诉你如何做:使用级联注释。这并不妨碍您使用JPA映射注释。您只需要使用这个额外的Hibernate注释来指定一个在JPA中不存在的级联选项。 - JB Nizet
@Cascade注释是专门针对Hibernate的,因此不适用于仅使用JPA(就像OP所要求的那样)。 - Alkanshel
2
@Amalgovinus 你没有理解重点:没有办法使用标准的JPA级联类型来级联一个操作(SAVE_UPDATE),因为它是Hibernate特有的,而在JPA中不存在。所以,要么停止使用Hibernate特定的操作,如SAVE_UPDATE(使用persist/merge),然后可以使用标准的JPA级联选项,要么接受使用Hibernate特定的操作,因此还需要使用Hibernate特定的注释。OP接受了答案,所以我认为答案是他想要的。 - JB Nizet

9

CascadeType.ALL 包含了 CascadeType.REMOVE。 解决方法是使用除了 CascadeType.REMOVE 之外的所有 CascadeType.*,如下所示:

@ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.REFRESH, CascadeType.MERGE}))

在您的UserGroup定义中。


1

当从子实体传播到父实体时,这几乎总是一种代码异味,应该反过来。

来自级联最佳实践

级联仅对父-子关联有意义(将父实体状态转换级联到其子实体)。从子到父的级联并不是很有用,通常是一种映射代码异味。

来自Hibernate最佳实践

12. 避免在大型关系中使用级联删除 大多数开发人员(包括我自己)看到关系的CascadeType.REMOVE定义时会有点紧张。它告诉Hibernate在删除此实体时也删除相关实体。总是有一种担心,相关实体也使用级联删除来处理其某些关系,Hibernate可能会删除比预期更多的数据库记录。在我使用Hibernate的所有年份中,这从未发生过,我认为这不是一个真正的问题。但是,级联删除使得理解删除实体时确切发生了什么变得非常困难。这是您应该始终避免的。如果您更仔细地查看Hibernate如何删除相关实体,您将找到另一个避免使用级联删除的原因。Hibernate为每个相关实体执行2个SQL语句:1个SELECT语句从数据库中获取实体,1个DELETE语句将其删除。如果只有1或2个相关实体,则可能没有问题,但如果有大量相关实体,则会创建性能问题。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接