【发布时间】:2017-06-26 17:09:21
【问题描述】:
所以,我有这种情况,我需要获取标题记录,删除它的详细信息,然后以不同的方式重新创建详细信息。更新细节太麻烦了。
我基本上有:
@Transactional
public void create(Integer id, List<Integer> customerIDs) {
Header header = headerService.findOne(id);
// header is found, has multiple details
// Remove the details
for(Detail detail : header.getDetails()) {
header.getDetails().remove(detail);
}
// Iterate through list of ID's and create Detail with other objects
for(Integer id : customerIDs) {
Customer customer = customerService.findOne(id);
Detail detail = new Detail();
detail.setCustomer(customer);
header.getDetails().add(detail);
}
headerService.save(header);
}
现在,数据库有如下约束:
Header
=================================
ID, other columns...
Detail
=================================
ID, HEADER_ID, CUSTOMER_ID
Customer
=================================
ID, other columns...
Constraint: Details must be unique by HEADER_ID and CUSTOMER_ID so:
Detail (VALID)
=================================
1, 123, 10
2, 123, 12
Detail (IN-VALID)
=================================
1, 123, 10
1, 123, 10
好的,当我运行它并传入 2、3、20 等客户时,它会创建所有 Detail 记录,只要之前没有记录。
如果我再次运行它,传入不同的客户列表,我希望首先删除 ALL 详细信息,然后创建 NEW 详细信息列表。
但是发生的事情是删除似乎在创建之前没有得到尊重。因为错误是重复键约束。重复键就是上面的“IN-VALID”场景。
如果我用一堆详细信息手动填充数据库并注释掉CREATE details 部分(仅运行删除),那么记录被删除就好了。所以删除有效。创作作品。只是两者不能一起工作。
我可以提供更多需要的代码。我正在使用Spring Data JPA。
谢谢
更新
我的实体基本上用以下注释:
@Entity
@Table
public class Header {
...
@OneToMany(mappedBy = "header", orphanRemoval = true, cascade = {CascadeType.ALL}, fetch = FetchType.EAGER)
private Set<Detail> Details = new HashSet<>();
...
}
@Entity
@Table
public class Detail {
...
@ManyToOne(optional = false)
@JoinColumn(name = "HEADER_ID", referencedColumnName = "ID", nullable = false)
private Header header;
...
}
更新 2
@克劳斯·格罗恩贝克
其实,我一开始并没有提到这一点,但我第一次是这样说的。另外,我正在使用 Cascading.ALL,我认为它包括 PERSIST。
只是为了测试,我已将我的代码更新为以下内容:
@Transactional
public void create(Integer id, List<Integer> customerIDs) {
Header header = headerService.findOne(id);
// Remove the details
detailRepository.delete(header.getDetails()); // Does not work
// I've also tried this:
for(Detail detail : header.getDetails()) {
detailRepository.delete(detail);
}
// Iterate through list of ID's and create Detail with other objects
for(Integer id : customerIDs) {
Customer customer = customerService.findOne(id);
Detail detail = new Detail();
detail.setCustomer(customer);
detail.setHeader(header);
detailRepository.save(detail)
}
}
再次......我想重申......如果我没有立即创建,删除将起作用。如果我在它之前没有删除,则创建将起作用。但是如果它们在一起,由于数据库中的重复键约束错误,两者都不会起作用。
我尝试过使用和不使用级联删除的相同方案。
【问题讨论】:
-
这取决于您如何映射详细信息...只是简单地
.remove(...)他们并不总是删除数据库中的行 -
所以你必须为你的实体提供注释
-
不确定为什么我的票数接近?无论如何...... @Andremoniy 是的,我已经用 Cascade 注释了我的实体。我将使用该信息更新问题。
-
是我,我撤回了我的投票
-
我没有意识到插入总是发生在删除之前,即使您先执行删除也是如此。在每个进程之间刷新 EM 就可以了。
标签: java spring jpa persistence