免责声明:这是我的第一个 Java 项目;边走边学。
背景:我继承了一个旧数据库,并在其上构建新的 RESTful API。我们正在使用Elide使用 Spring Boot 提供JSON API合规服务。
问题:我们的实体通过连接表相互之间以及它们自身之间存在多对多关系。考虑以下模式:
CREATE TABLE ALPHA (
ID VARCHAR(255),
NAME VARCHAR(255),
CONSTRAINT PK_ALPHA PRIMARY KEY (ID)
);
CREATE TABLE BRAVO (
ID VARCHAR(255),
NAME VARCHAR(255),
CONSTRAINT PK_BRAVO PRIMARY KEY (ID)
);
CREATE TABLE RELATIONSHIP (
ID INT AUTO_INCREMENT,
FROM_ID VARCHAR(255),
TO_ID VARCHAR(255)
);
其中资源实体建模如下:
public class Alpha implements Serializable {
private String id;
private String name;
private Set<Alpha> alphas = new HashSet<>();
private Set<Bravo> bravos = new HashSet<>();
@Id
@Column(name = "ID", unique = true, nullable = false)
@GeneratedValue(generator = "uuid")
@GenericGenerator(name = "uuid", strategy = "uuid")
public String getId() {
return id;
}
public String getName() {
return name;
}
@ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
@JoinTable(
name = "RELATIONSHIP",
joinColumns = @JoinColumn(name = "FROM_ID"),
inverseJoinColumns = @JoinColumn(name = "TO_ID")
)
public Set<Alpha> getAlphas() {
return alphas;
}
@ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
@JoinTable(
name = "RELATIONSHIP",
joinColumns = @JoinColumn(name = "FROM_ID"),
inverseJoinColumns = @JoinColumn(name = "TO_ID")
)
public Set<Bravo> getBravos() {
return bravos;
}
}
以及关系表:
public class Relationship implements Serializable {
private Integer id;
private String fromId;
private String toId;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
public Integer getId() {
return id;
}
@Column(name = "FROM_ID")
public String getFromId() {
return fromId;
}
@Column(name = "TO_ID")
public String getToId() {
return toId;
}
}
现在假设我们有一个 Alpha
记录A1
与 A2
的关系, A3
, B1
,和B2
。首先我们删除与A2
的关系.
从我们的 API 来看,这将是 DELETE
请求http://localhost:9000/api/alphas/a1/relationships/alphas
与 body
{
"data": [
{
"type": "alphas",
"id": "a2"
}
]
}
Hibernate 在幕后执行我所期望的操作并生成以下 SQL 查询:
2018-07-13 09:48:23.687 DEBUG 7964 --- [nio-9000-exec-5] org.hibernate.SQL :
Hibernate:
select
alpha0_.id as id1_0_,
alpha0_.name as name2_0_
from
alpha alpha0_
where
alpha0_.id in (
?
)
2018-07-13 09:48:23.688 TRACE 7964 --- [nio-9000-exec-5] o.h.type.descriptor.sql.BasicBinder : binding parameter [1] as [VARCHAR] - [a1]
2018-07-13 09:48:23.690 DEBUG 7964 --- [nio-9000-exec-5] org.hibernate.SQL :
Hibernate:
select
alphas0_.from_id as from_id2_2_0_,
alphas0_.to_id as to_id3_2_0_,
alpha1_.id as id1_0_1_,
alpha1_.name as name2_0_1_
from
relationship alphas0_
inner join
alpha alpha1_
on alphas0_.to_id=alpha1_.id
where
alphas0_.from_id=?
2018-07-13 09:48:23.690 TRACE 7964 --- [nio-9000-exec-5] o.h.type.descriptor.sql.BasicBinder : binding parameter [1] as [VARCHAR] - [a1]
2018-07-13 09:48:23.699 DEBUG 7964 --- [nio-9000-exec-5] org.hibernate.SQL :
Hibernate:
select
alpha0_.id as id1_0_,
alpha0_.name as name2_0_
from
alpha alpha0_
where
alpha0_.id in (
?
)
2018-07-13 09:48:23.699 TRACE 7964 --- [nio-9000-exec-5] o.h.type.descriptor.sql.BasicBinder : binding parameter [1] as [VARCHAR] - [a2]
2018-07-13 09:48:23.721 DEBUG 7964 --- [nio-9000-exec-5] org.hibernate.SQL :
Hibernate:
delete
from
relationship
where
from_id=?
and to_id=?
2018-07-13 09:48:23.722 TRACE 7964 --- [nio-9000-exec-5] o.h.type.descriptor.sql.BasicBinder : binding parameter [1] as [VARCHAR] - [a1]
2018-07-13 09:48:23.724 TRACE 7964 --- [nio-9000-exec-5] o.h.type.descriptor.sql.BasicBinder : binding parameter [2] as [VARCHAR] - [a2]
关键部分是delete from relationship where from_id=? and to_id=?
现在尝试删除第二个 Alpha
时出现问题关系A3
,其中 Hibernate 执行几乎完全相同的序列,除了 DELETE
之外。省略 and to_id=?
的查询从查询中,即
Hibernate:
delete
from
relationship
where
from_id=?
这会产生删除所有其他 A1
的意外后果表中的关系,即B1
和B2
.
这就是我问题的症结所在。看来 Hibernate 只看到了另一个相关的 Alpha
记录,因此决定通过省略 and to_id
来简化查询声明。
我可能错过了一些非常明显的东西!
我还应该指出,我尝试在 relationship
上使用复合键表但无济于事。
最佳答案
这是一个不寻常的设计,我怀疑它混淆了 Hibernate
。在多个多对多
关系之间共享单个联接表并不是好的数据库设计,因为它不能具有任何外键/引用完整性。
其次,Hibernate
管理关系,因此可以控制 @JoinTable
,我不知道它如何处理与同一个表映射的多个实体关系。显然,情况不太好!
最简单的解决方案(如果可以的话)是有 2 个映射表。一个是 Alpha-Alpha
之间的关系,另一个是 Alpha-Bravo
之间的关系。
关于java - JPA/hibernate : ManyToMany delete relation on Join Table,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51329827/