java - Hibernate 自动删除表中的行而没有明确告知?(@ManyToMany 协会,Spring JPA)
问题描述
我正在开发一个基于微服务的 Spring JPA 项目,其中我有两个实体,UserEntity 和 RegionEntity,通过多对多关系关联。在两个实体的(简化)代码下方:
@EqualsAndHashCode(of = {"id"})
@Data
@Entity
@Table(name = "users")
@Audited
public class UserEntity implements Serializable {
@Id
@Column(name = "userId", columnDefinition = "int", unique = true, nullable = false)
private Long id;
@NotAudited
@ManyToMany(fetch = FetchType.EAGER)
@JoinTable(name = "users_regions",
joinColumns = @JoinColumn(name = "userId", columnDefinition = "int", nullable = false, updatable = false),
inverseJoinColumns = @JoinColumn(name = "regionId", columnDefinition = "varchar(50)", nullable = false, updatable = false))
private Set<RegionEntity> regions = new HashSet<>();
}
@EqualsAndHashCode(exclude = {"users"})
@Entity
@Table(name = "regions")
@Data
@Audited
public class RegionEntity {
@Id
@Column(name = "name", columnDefinition = "varchar(50)", unique = true, nullable = false)
private String name;
@ManyToMany(mappedBy = "regions", fetch = FetchType.EAGER)
private Set<UserEntity> users = new HashSet<>();
}
现在,我有一个用于持久化第三个实体 CallEntity 实例的路由,它利用了前面的两个实体。知道 CallEntity 还与 RegionEntity 具有多对多关联以及与 user 具有多对一关联可能很有用。简而言之,这是路由调用的方法。
public CallDTO myMethod(String userName, /* ... more stuff */) {
UserProjection userProj = userConsumer.findByUserName(userName, UserBasicProjection.class); // from another repository, retrieve a user projection
UserEntity user = userRepository.findById(user.getId()).orElse(null); // use that projection to initialise the user
Set<RegionEntity> userRegions = user != null ? user.getRegions() : null;
CallEntity newCall = new CallEntity();
/ * some actions, mainly setting values for newCall using userRegions and user... */
CallEntity call = callRepository.save(newCall);
return callMapper.toDTO(call);
}
问题是 Hibernate 在保存 CallEntity 对象时会自动删除关联表中与用户区域对相关的行。例如,如果用户的 id 为 1234,并且关联了区域 A、B 和 C,
user | region
-------------
1234 | A
-------------
1234 | B
-------------
1234 | C
-------------
那么这行代码之后的表中的所有三行都将被删除:
CallEntity call = callRepository.save(newCall);
被执行。
这是当前使用的 Hibernate 版本:
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-jpamodelgen</artifactId>
<version>5.3.12.Final</version>
</dependency>
这是执行后的控制台打印输出:
Hibernate:
/* get current state package-name.UserEntity */ select
userent_.userId
from
user userent_
where
userent_.userId=?
Hibernate:
/* get current state package-name.RegionEntity */ select
regione_.name
from
region regione_
where
regione_.name=?
Hibernate:
/* insert package-name.CallEntity
*/ insert
into
call
(id, userid, regionid)
values
(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
Hibernate:
select
last_insert_id()
Hibernate:
/* delete collection package-name.UserEntity.regions */ delete
from
users_regions
where
userId=?
Hibernate:
/* insert collection
row package-name.CallEntity.userRegions */ insert
into
call_region
(id, name)
values
(?, ?)
我发现如果我改变关系的方向(在这种情况下,拥有实体是 RegionEntity)问题就会消失。然而,这绝不是一个可行的解决方案,因为它会影响项目的其他部分。另外,我发现之前在这个网站上问过一个类似的问题(ManyToMany assoicate delete join table entry),但不幸的是答案并不令人满意。我尝试添加和使用便捷方法来正确建立关联(正如链接问题的答案所暗示的那样),但这不起作用。
任何帮助将不胜感激。
谢谢你。
解决方案
最后,通过将一组区域包装在一个副本中解决了这个问题。
也就是说,通过替换这一行:
设置 userRegions = user != null ?user.getRegions() : null;
和:
设置 userRegions = userxpc != null ?Set.copyOf(userxpc.getRegions()) : null;
推荐阅读
- asp.net-core - Unobtrusive Ajax lib 不发送 XmlHttpRequest 标头
- spring-cloud-config - 带有裸本地存储库的 Spring-Cloud-Config
- visual-studio - Resource.Designer.cs 生成器在调试时缺少资源
- reactjs - 如何动态更改属性要求
- sql-server-2008 - 从其他数据集向 SQL Server Reporting Services 中的表添加值
- database - Neo4j - Find nodes who never had any relationship with a different node
- java - 验证方法被调用并中断执行/忽略以后的失败
- microsoft-graph-api - 调用 OneDrive 图形 API 时出现异常
- php - 如何从 Wordpress ACF - 灵活内容字段中获取发布对象数据
- wso2 - 如何使用 WSO2 将动态值传递给 Sql