JPA + @OneToMany + DELETE:如果我稍后访问父级,则不会删除项目
JPA + @OneToMany + DELETE: Item is not deleted if I access parent later
我有一个 Deal
可以有多个 DealItems
.
DealItems
在 Deal
中使用以下 JPA 注释链接:
public class DealEntity extends BasicEntity {
@OneToMany(mappedBy = "deal", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private List<DealItemEntity> items;
...
这是DealItem
中的关系:
public class DealItemEntity extends BasicEntity {
@ManyToOne
@JoinColumn(name = "deal_id", nullable = false)
private DealEntity deal;
...
当我删除一个DealItem
时,它会被删除并再次保留,当我在删除后访问Deal
时,请看这里:
public FullDealResponse deleteDealItem(final String dealCode, final long dealItemId) {
DealEntity dealEntity = dealControl.findDealByDealCode(dealCode);
if (dealEntity == null) {
throw new WorkbenchGenericErrorException("Deal not found");
}
DealItemEntity dealItemEntity = dealItemControl.findDealItemByIdAndDealId(dealItemId, dealEntity.getId());
if (dealItemEntity == null) {
throw new WorkbenchGenericErrorException("Deal item not found");
}
// this makes a database DELETE call that is executed after the session is done
dealItemControl.deleteDealItem(dealItemEntity);
// When I remove this and I do not return anything, the deletion works
return this.getFullDealResponse(dealEntity);
}
编辑:
这是 getFullDealResponse()
和 getFullDealItemResponse()
:
private FullDealResponse getFullDealResponse(final DealEntity dealEntity) {
FullDealResponse response = new FullDealResponse();
response.setDescription(dealEntity.getDescription());
response.setTitle(dealEntity.getTitle());
response.setDealCode(dealEntity.getDealCode());
response.setCreatedAt(dealEntity.getCreatedAt());
response.setUpdatedAt(dealEntity.getUpdatedAt());
// get related items
List<FullDealItemResponse> itemsResponse = new ArrayList<FullDealItemResponse>();
for (DealItemEntity dealItemEntity : dealEntity.getItems()) {
itemsResponse.add(this.getFullDealItemResponse(dealItemEntity));
}
response.setItems(itemsResponse);
return response;
}
private FullDealItemResponse getFullDealItemResponse(final DealItemEntity dealItemEntity) {
FullDealItemResponse response = new FullDealItemResponse();
response.setId(dealItemEntity.getId());
response.setDescription(dealItemEntity.getDescription());
response.setTitle(dealItemEntity.getTitle());
response.setCreatedAt(dealItemEntity.getCreatedAt());
response.setUpdatedAt(dealItemEntity.getUpdatedAt());
return response;
}
这是deleteDealItem()
和delete()
函数:
public void deleteDealItem(final DealItemEntity dealItemEntity) {
super.delete(DealItemEntity.class, dealItemEntity.getId());
}
protected void delete(final Class<?> type, final Object id) {
Object ref = this.em.getReference(type, id);
this.em.remove(ref);
}
当我切换 CascadeType
时可以解决这个问题吗?如果可以,哪种类型是正确的?或者我是否必须迭代 Deal.getItems()
,删除不需要的项目,使用 Deal.setItems()
设置新列表并仅更新 Deal
以便传播删除?
执行此操作的首选方法是什么?
I have replicated this code locally and verified my explanation
总结:
级联没有影响。即使你去掉你的级联操作,把每一项单独保存,那么当你来到这个方法的时候,它不会删除你的项。
无论 deal.getItems
初始化如何都具有相同的行为,除了直接删除 dealItem 之外,您还必须通过从 deal.getItems
中删除它来删除 dealItem
.
在双向关系中,您必须明确管理双方。完全相同的方式,您将 dealItem 添加到 deal 并在保存之前设置 dealItem 的 deal 字段。
总体解释
JPA 只能有一个与其会话关联的特定项目的表示。
它是提供Repeatble Read, Dirty Checking等的基础
JPA 还跟踪与其会话关联的每个对象,如果任何被跟踪的对象发生更改,它们将在事务提交时刷新。
当只有 deal
对象(带有惰性 deaItems
集合)和直接获取的 dealItem
是唯一与会话关联的两个实体时,JPA 具有会话中每个演示文稿,因为没有冲突,当您删除它时,它会通过 dealItemControl.deleteDealItem
删除它 dealItem is deleted
但是,一旦您调用 deal.getItems
,JPA 不仅管理交易,而且还管理与 deal
对象相关联的每个 个交易项 .因此,当您删除 dealItemControl.deleteDealItem
时,JPA 会出现问题,因为 deal.getItems 告诉它未标记为删除。所以删除没有发出。
参考:生成的JPA QL也证实了我的解释
1. deal.getItems
和生成的查询
@OneToMany(mappedBy = "deal", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private List<DealItemEntity> items;
DealEntity dealEntity = dealControl.findDealByDealCode(dealCode);
....
dealItemControl.deleteDealItem(dealItemEntity);
....
dealEntity.getItems()
select deal0_.* from deal deal0_ where deal0_.id=?
select dealitem0_.*
deal1_.*
from
deal_item dealitem0_ inner join deal deal1_ on dealitem0_.deal_id=deal1_.id
where
dealitem0_.id=?
select items0_.* from deal_item items0_ where items0_.deal_id=?
2。没有 deal.getItems
和生成的查询
@OneToMany(mappedBy = "deal", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private List<DealItemEntity> items;
DealEntity dealEntity = dealControl.findDealByDealCode(dealCode);
....
dealItemControl.deleteDealItem(dealItemEntity);
select deal0_.* from deal deal0_ where deal0_.id=?
select dealitem0_.*
deal1_.*
from
deal_item dealitem0_ inner join deal deal1_ on dealitem0_.deal_id=deal1_.id
where
dealitem0_.id=?
delete from deal_item where id=?
我有一个 Deal
可以有多个 DealItems
.
DealItems
在 Deal
中使用以下 JPA 注释链接:
public class DealEntity extends BasicEntity {
@OneToMany(mappedBy = "deal", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private List<DealItemEntity> items;
...
这是DealItem
中的关系:
public class DealItemEntity extends BasicEntity {
@ManyToOne
@JoinColumn(name = "deal_id", nullable = false)
private DealEntity deal;
...
当我删除一个DealItem
时,它会被删除并再次保留,当我在删除后访问Deal
时,请看这里:
public FullDealResponse deleteDealItem(final String dealCode, final long dealItemId) {
DealEntity dealEntity = dealControl.findDealByDealCode(dealCode);
if (dealEntity == null) {
throw new WorkbenchGenericErrorException("Deal not found");
}
DealItemEntity dealItemEntity = dealItemControl.findDealItemByIdAndDealId(dealItemId, dealEntity.getId());
if (dealItemEntity == null) {
throw new WorkbenchGenericErrorException("Deal item not found");
}
// this makes a database DELETE call that is executed after the session is done
dealItemControl.deleteDealItem(dealItemEntity);
// When I remove this and I do not return anything, the deletion works
return this.getFullDealResponse(dealEntity);
}
编辑:
这是 getFullDealResponse()
和 getFullDealItemResponse()
:
private FullDealResponse getFullDealResponse(final DealEntity dealEntity) {
FullDealResponse response = new FullDealResponse();
response.setDescription(dealEntity.getDescription());
response.setTitle(dealEntity.getTitle());
response.setDealCode(dealEntity.getDealCode());
response.setCreatedAt(dealEntity.getCreatedAt());
response.setUpdatedAt(dealEntity.getUpdatedAt());
// get related items
List<FullDealItemResponse> itemsResponse = new ArrayList<FullDealItemResponse>();
for (DealItemEntity dealItemEntity : dealEntity.getItems()) {
itemsResponse.add(this.getFullDealItemResponse(dealItemEntity));
}
response.setItems(itemsResponse);
return response;
}
private FullDealItemResponse getFullDealItemResponse(final DealItemEntity dealItemEntity) {
FullDealItemResponse response = new FullDealItemResponse();
response.setId(dealItemEntity.getId());
response.setDescription(dealItemEntity.getDescription());
response.setTitle(dealItemEntity.getTitle());
response.setCreatedAt(dealItemEntity.getCreatedAt());
response.setUpdatedAt(dealItemEntity.getUpdatedAt());
return response;
}
这是deleteDealItem()
和delete()
函数:
public void deleteDealItem(final DealItemEntity dealItemEntity) {
super.delete(DealItemEntity.class, dealItemEntity.getId());
}
protected void delete(final Class<?> type, final Object id) {
Object ref = this.em.getReference(type, id);
this.em.remove(ref);
}
当我切换 CascadeType
时可以解决这个问题吗?如果可以,哪种类型是正确的?或者我是否必须迭代 Deal.getItems()
,删除不需要的项目,使用 Deal.setItems()
设置新列表并仅更新 Deal
以便传播删除?
执行此操作的首选方法是什么?
I have replicated this code locally and verified my explanation
总结:
级联没有影响。即使你去掉你的级联操作,把每一项单独保存,那么当你来到这个方法的时候,它不会删除你的项。
无论
deal.getItems
初始化如何都具有相同的行为,除了直接删除 dealItem 之外,您还必须通过从deal.getItems
中删除它来删除dealItem
.在双向关系中,您必须明确管理双方。完全相同的方式,您将 dealItem 添加到 deal 并在保存之前设置 dealItem 的 deal 字段。
总体解释
JPA 只能有一个与其会话关联的特定项目的表示。
它是提供Repeatble Read, Dirty Checking等的基础
JPA 还跟踪与其会话关联的每个对象,如果任何被跟踪的对象发生更改,它们将在事务提交时刷新。
当只有
deal
对象(带有惰性deaItems
集合)和直接获取的dealItem
是唯一与会话关联的两个实体时,JPA 具有会话中每个演示文稿,因为没有冲突,当您删除它时,它会通过dealItemControl.deleteDealItem
删除它 dealItem is deleted但是,一旦您调用
deal.getItems
,JPA 不仅管理交易,而且还管理与deal
对象相关联的每个 个交易项 .因此,当您删除dealItemControl.deleteDealItem
时,JPA 会出现问题,因为 deal.getItems 告诉它未标记为删除。所以删除没有发出。
参考:生成的JPA QL也证实了我的解释
1. deal.getItems
和生成的查询
@OneToMany(mappedBy = "deal", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private List<DealItemEntity> items;
DealEntity dealEntity = dealControl.findDealByDealCode(dealCode);
....
dealItemControl.deleteDealItem(dealItemEntity);
....
dealEntity.getItems()
select deal0_.* from deal deal0_ where deal0_.id=?
select dealitem0_.*
deal1_.*
from
deal_item dealitem0_ inner join deal deal1_ on dealitem0_.deal_id=deal1_.id
where
dealitem0_.id=?
select items0_.* from deal_item items0_ where items0_.deal_id=?
2。没有 deal.getItems
和生成的查询
@OneToMany(mappedBy = "deal", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private List<DealItemEntity> items;
DealEntity dealEntity = dealControl.findDealByDealCode(dealCode);
....
dealItemControl.deleteDealItem(dealItemEntity);
select deal0_.* from deal deal0_ where deal0_.id=?
select dealitem0_.*
deal1_.*
from
deal_item dealitem0_ inner join deal deal1_ on dealitem0_.deal_id=deal1_.id
where
dealitem0_.id=?
delete from deal_item where id=?