我的问题是:Project和Employee这两个表之间存在多对多关系。有一个更新给定员工的选项,但有一个小问题。更新员工后,hibernate会自动从连接的project_eemployee表中删除该员工的记录。
Hibernate:更新员工设置电子邮件=?,first_name=?,last_name=?employee_id=在哪里?
这发生在之后
Hibernate:从项目employee_id=中删除?
我正在学习一门课程,刚刚注意到这个错误。讲师的源代码在这里:
https://github.com/imtiazahmad007/spring-framework-course
我已经检查了你的github页面:
@ManyToMany(cascade = {CascadeType.DETACH, CascadeType.MERGE, CascadeType.REFRESH, CascadeType.PERSIST},
fetch = FetchType.LAZY)
@JoinTable(name="project_employee",
joinColumns=@JoinColumn(name="employee_id"),
inverseJoinColumns= @JoinColumn(name="project_id")
)
@JsonIgnore
private List<Project> projects;
级联类型。合并+级联类型。PERSIST的意思是,如果保存了Employee实体,则必须保存Project实体引用。
在许多情况下,这意味着:
- 通过外键删除
- 批量插入
如果没有大容量插入,则说明持久性上下文存在问题(您正在保存一个具有空项目集合的实体(。
可能的解决方案:
- 删除级联类型。合并+级联类型。如果您不想每次保存Employee时都更改项目,请坚持。您仍然可以通过存储库保存收集
- 确保在保存操作时附加了集合。这将导致Delete+Insert,但结果会正常
- 使用EmbeddedId将多对多更改为一对多
请参阅文档:
当实体从@ManyToMany集合中删除时,Hibernate只需删除链接表中的连接记录。不幸的是,此操作需要删除与给定父级关联的所有条目,并重新创建当前运行的持久上下文中列出的条目。
https://docs.jboss.org/hibernate/orm/5.6/userguide/html_single/Hibernate_User_Guide.html#associations-多对多
***从下面的对话框更新以使级联清晰。
比方说,你有两个实体A&B(省略getter和setter(。+回购
@Entity
@Table(name = "a")
public class A {
@Id
private Integer id;
private String name;
@ManyToMany(cascade = {CascadeType.ALL})
@JoinTable(name="a_b",
joinColumns=@JoinColumn(name="a_id"),
inverseJoinColumns= @JoinColumn(name="b_id")
)
private List<B> bs;
}
@Entity
@Table(name = "b")
public class B {
@Id
private Integer id;
private String name;
}
您的样本测试如下:
@Test
public void testSave() {
B b = new B();
b.setId(1);
b.setName("b");
b = bRepository.save(b);
A a = new A();
a.setId(1);
a.setName("a");
a.setBs(Collections.singletonList(b));
aRepository.save(a);
a.setName("new");
service.save(a); //watch sevice implementations below
}
版本1:
@Transactional
public void save(A a) {
aRepository.save(a);
}
休眠日志如下:
Hibernate:
update
a
set
name=?
where
id=?
Hibernate:
delete
from
a_b
where
a_id=?
Hibernate:
insert
into
a_b
(a_id, b_id)
values
(?, ?)
删除+大容量插入存在(尽管事实上,B-s实际上没有改变(
版本2:
@Transactional
public void save(A a) {
Optional<A> existing = aRepository.findById(a.getId());
if (existing.isPresent()) {
a.setBs(existing.get().getBs());
}
aRepository.save(a);
}
日志:
update
a
set
name=?
where
id=?
在这里,b-collection被强制重新附加,所以hibernate明白,它不需要级联。