Java JPA 2 / Hibernate 孤儿删除仍然无法与@OneToMany 一起使用?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/24579374/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-14 13:10:25  来源:igfitidea点击:

JPA 2 / Hibernate orphan removal still not working with @OneToMany?

javahibernatejpaormorphan

提问by Eric B.

I'm trying to use orphanRemoval in Hibernate 4.3.5 / JPA2 objects but it does not seem to be working as I expected. I am not sure, however, if I am doing something incorrect, or if this is still a bug in Hibernate.

我正在尝试在 Hibernate 4.3.5 / JPA2 对象中使用 orphanRemoval 但它似乎没有按我预期的那样工作。但是,我不确定我是否做错了什么,或者这是否仍然是 Hibernate 中的错误。

Given the following relationships (@Version, getters and setters omitted for brevity):

鉴于以下关系(为简洁起见,省略了@Version、getter 和 setter):

@Entity
public class Provider implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "id")
    private Long id;

    private String name;

    @OneToMany(orphanRemoval=true,cascade=CascadeType.REMOVE)
    @JoinColumn(name="provider_id", referencedColumnName="id")
    private List<Contract> contracts;
}


@Entity
public class Contract implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "id")
    private Long id;

    private String volume;

    @OneToMany(orphanRemoval=true,cascade=CascadeType.REMOVE) // delete any attachments that were previously uploaded with this contract
    @JoinTable(name="contract_attachment", joinColumns = @JoinColumn(name = "contract_id", referencedColumnName = "id"), inverseJoinColumns = @JoinColumn(name = "attachment_id", referencedColumnName = "id"))
    private List<Attachment> attachments;
}

@Entity
public class Attachment implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "id")
    private Long id;

    private String filename;
}

I would expect that if I remove a contract from the Provider.contracts list, that it would delete corresponding rows from the contract table and all associated attachments from the attachment table. However, only the contract table gets deleted. The attachment table is not modified.

我希望如果我从 Provider.contracts 列表中删除一个合同,它会从合同表中删除相应的行以及从附件表中删除所有关联的附件。但是,只有合同表被删除。不修改附件表。

Ex:

前任:

    // loop over all contracts and delete the one with the matching id
    for(Iterator<Contract> it = provider.getContracts().iterator(); it.hasNext();){
        Contract c = it.next();
        if( c.getId() == contractId ){
            it.remove();
            break;
        }
    }

Given that the attachments are ManyToOne relative to the Contract table, if the Contract is deleted, then the attachments are orphaned. But even with the orphanRemoval=true, this does not delete the rows from the DB.

鉴于附件相对于合同表是多对一的,如果合同被删除,则附件是孤立的。但即使使用orphanRemoval=true,这也不会从数据库中删除行。

I found several issues relating to this for Hibernate 3 (both here on SO, and Jira and elsewhere online), but I had understood that it was fixed in Hibernate 4. But using Hibernate 4.3.5 I am still seeing this issue. From this issue, it seems to work, so I am not sure why I cannot get it functional.

我在 Hibernate 3 上发现了几个与此相关的问题(在 SO 上、Jira 和其他在线内容上),但我知道它已在 Hibernate 4 中修复。但是使用 Hibernate 4.3.5 我仍然看到这个问题。从这个问题来看,它似乎有效,所以我不确定为什么我不能让它发挥作用。

Is there something wrong/missing in my code, or is Hibernate still problematic? Am I required to implement equalsand hashCodein any of these entity classes for orphanRemovalto work properly? I tried implementing both methods in Contract and Attachment, but has made no difference.

我的代码中是否有错误/缺失,或者 Hibernate 仍然存在问题?我是否需要实施equalshashCode在这些实体类的orphanRemoval工作是否正常?我尝试在 Contract 和 Attachment 中实现这两种方法,但没有任何区别。

Looking at the Hibernate logs, it shows Hibernate making the changes to the join table (or FK mapping), but does not actually delete the row from the associated table. I can see Hibernate setting the provider_id=null in the Contract table, but shouldn't it be deleting the Contract row instead?

查看 Hibernate 日志,它显示 Hibernate 对连接表(或 FK 映射)进行了更改,但实际上并未从关联表中删除该行。我可以看到 Hibernate 在 Contract 表中设置了 provider_id=null,但它不应该删除 Contract 行吗?

2014-07-04 15:06:41,333 [main] [-] DEBUG org.hibernate.SQL - 
    /* update
        com.ia.domain.Provider */ update
            provider 
        set
            default_contact_id=?,
            name=?,
            type=?,
            version=?,
            website=? 
        where
            id=? 
            and version=?
Hibernate: 
    /* update
        com.ia.domain.Provider */ update
            provider 
        set
            default_contact_id=?,
            name=?,
            type=?,
            version=?,
            website=? 
        where
            id=? 
            and version=?
2014-07-04 15:06:41,334 [main] [-] TRACE hibernate.type.descriptor.sql.BasicBinder - binding parameter [1] as [BIGINT] - [null]
2014-07-04 15:06:41,334 [main] [-] TRACE hibernate.type.descriptor.sql.BasicBinder - binding parameter [2] as [VARCHAR] - [name_3]
2014-07-04 15:06:41,335 [main] [-] TRACE org.hibernate.type.EnumType - Binding [CARRIER] to parameter: [3]
2014-07-04 15:06:41,336 [main] [-] TRACE hibernate.type.descriptor.sql.BasicBinder - binding parameter [4] as [INTEGER] - [2]
2014-07-04 15:06:41,336 [main] [-] TRACE hibernate.type.descriptor.sql.BasicBinder - binding parameter [5] as [VARCHAR] - [website_3]
2014-07-04 15:06:41,337 [main] [-] TRACE hibernate.type.descriptor.sql.BasicBinder - binding parameter [6] as [BIGINT] - [4]
2014-07-04 15:06:41,338 [main] [-] TRACE hibernate.type.descriptor.sql.BasicBinder - binding parameter [7] as [INTEGER] - [1]
2014-07-04 15:06:41,342 [main] [-] DEBUG org.hibernate.SQL - 
    /* delete one-to-many com.ia.domain.Provider.contracts */ update
            contract 
        set
            provider_id=null 
        where
            provider_id=?
Hibernate: 
    /* delete one-to-many com.ia.domain.Provider.contracts */ update
            contract 
        set
            provider_id=null 
        where
            provider_id=?
2014-07-04 15:06:41,344 [main] [-] TRACE hibernate.type.descriptor.sql.BasicBinder - binding parameter [1] as [BIGINT] - [4]

采纳答案by Maciej Dobrowolski

Honestly, I don't know why, but if you add CascadeType.PERSIST(or better CascadeType.ALL) to your @OneToManyrelationship in Providerentity it will work as expected.

老实说,我不知道为什么,但是如果您将CascadeType.PERSIST(或更好CascadeType.ALL)添加到实体中的@OneToMany关系中Provider,它将按预期工作。

Probably the Hibernate documentation is lacking in this little detail.

可能 Hibernate 文档缺少这个小细节。

updateEclipseLink 2.5.1 with JPA2 does not seem to have this issue

使用 JPA2更新EclipseLink 2.5.1 似乎没有这个问题

2nd update

第二次更新

In Section 2.9, Entity Relationships, the JPA 2.1 spec says: "If the entity being orphaned is a detached, new, or removed entity, the semantics of orphanRemoval do not apply."

在第 2.9 节实体关系中,JPA 2.1 规范说:“如果被孤立的实体是分离的、新的或删除的实体,则 orphanRemoval 的语义不适用。”

I don't know if your related entities are detached, but if yes then it's not a bug :)

我不知道您的相关实体是否已分离,但如果是,则不是错误 :)

回答by dsrajput

I am also getting the issue stated. Though it has been deprecated, below use is working fine with orphan removal:

我也收到了这个问题。虽然它已被弃用,但下面的使用与孤儿删除工作正常:

@org.hibernate.annotations.Cascade(org.hibernate.annotations.CascadeType.DELETE_ORPHAN)