java - JPA + @OneToMany + 删除 : Item is not deleted if I access parent later

标签 java postgresql hibernate jpa cascade

我得到了一个Deal,它可以有多个DealItems

DealItemsDeal 中使用以下 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

摘要:

  1. 级联没有影响。即使你去掉你的级联操作,单独保存每个项目,那么当你来到这个方法时,它也不会删除你的项目。

  2. 无论deal.getItems如何,都具有相同的行为初始化时,您必须删除 dealItem将其从 deal.getItems 中删除除了直接删除 dealItem 之外。

  3. 在双向关系中,您必须明确管理双方。完全相同的方式,您将 dealItem 添加到 deal 并在保存之前设置 dealItem 的 deal 字段。

总体说明

  • JPA 只能拥有与其 session 关联的特定项目的一种表示形式。

  • 它是提供重复读取、脏检查等功能的基础。

  • JPA 还跟踪与其 session 关联的每个对象,如果任何跟踪的对象发生更改,它们将在事务提交时刷新。

  • 仅当deal时对象(带有惰性 deaItems 集合)和直接获取的 dealItem是与 session 关联的唯一两个实体,那么 JPA 在 session 中为每个实体都有一个演示文稿,因为不存在冲突,所以当您删除它时,它会通过 dealItemControl.deleteDealItem 删除它。 dealItem 已删除

  • 但是,一旦您调用 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=?

关于java - JPA + @OneToMany + 删除 : Item is not deleted if I access parent later,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62498503/

相关文章:

java - 仅获取 HQL 查询中指定映射的数据

java - HttpClient 向 Nginx 服务器投诉 'NoHttpResponseException'

java - 如何从 CPython 调用 java 对象和函数?

java - 是否可以使用 JpaRepository<T, I> 在 jsp 中分页

sql - 如何使用postgres窗口函数计算会计软件中的余额

ruby-on-rails - 当我推送 Heroku 时,Sqlite3 出现问题

java - 保存一对一关系: Null pointer Exception

java - 如何查找包

sql - 防止在 Postgres 中为特定查询使用索引

java - Hibernate softdelete - 软删除时列索引超出范围异常