JPA 2 /休眠孤儿删除仍然不能与@OneToMany一起工作? [英] JPA 2 / Hibernate orphan removal still not working with @OneToMany?

查看:107
本文介绍了JPA 2 /休眠孤儿删除仍然不能与@OneToMany一起工作?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图在Hibernate 4.3.5 / JPA2对象中使用orphanRemoval,但它似乎没有像我期望的那样工作。我不确定,但是,如果我做了不正确的事情,或者这仍然是Hibernate中的错误。



考虑到以下关系(@Version,getters和setters省略:)

  @Entity 
public class Provider实现Serializable {

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

私人字符串名称;

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


$ b @Entity
public class Contract implements Serializable {

@Id
@GeneratedValue(strategy = GenerationType。 AUTO)
@Column(name =id)
私人长ID;

私有String卷;

@OneToMany(orphanRemoval = true,cascade = CascadeType.REMOVE)//删除以前用这个合同上传的任何附件
@JoinTable(name =contract_attachment,joinColumns = @JoinColumn (name =contract_id,referencedColumnName =id),inverseJoinColumns = @JoinColumn(name =attachment_id,referencedColumnName =id))
private List< Attachment>附件;
}

@Entity
公共类附件实现Serializable {

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name =id)
私人长ID;

私有字符串文件名;
}

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

例如:

  //循环所有合约,并删除具有匹配id 
的合同(Iterator< Contract> it = provider.getContracts()。iterator(); it.hasNext();){
Contract c = it 。下一个();
if(c.getId()== contractId){
it.remove();
休息;


$ / code>

鉴于附件是与合约表相关的ManyToOne ,如果合同被删除,那么附件是孤儿。但即使使用 orphanRemoval = true ,也不会删除数据库中的行。



我发现了几个问题与Hibernate 3相关(在SO和Jira以及其他在线上),但我已经理解它已经在Hibernate 4中修复了。但是使用Hibernate 4.3.5我仍然看到这个问题。从这个问题,它似乎工作,所以我不知道为什么我不能得到它的功能。



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



查看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 =?
其中
id =?
和version =?
Hibernate:
/ * update
com.ia.domain.Provider * / update
提供者
set
default_contact_id = ?,
名称=?,
type =?,
version = ?,
website =?
其中
id =?
和version =?
2014-07-04 15:06:41,334 [主] [ - ] TRACE hibernate.type.descriptor.sql.BasicBinder - 绑定参数[1] as [BIGINT] - [null]
2014- 07-04 15:06:41,334 [main] [ - ] TRACE hibernate.type.descriptor.sql.BasicBinder - 绑定参数[2] as [VARCHAR] - [name_3]
2014-07-04 15:06 :41,335 [main] [ - ] TRACE org.hibernate.type.EnumType - 绑定[CARRIER]参数:[3]
[main] [ - ] TRACE hibernate。 type.descriptor.sql.BasicBinder - 绑定参数[4]为[INTEGER] - [2]
[main] [ - ] TRACE hibernate.type.descriptor.sql。 BasicBinder - 绑定参数[5]为[VARCHAR] - [website_3]
TRACE hibernate.type.descriptor.sql.BasicBinder - 绑定参数[6] ]作为[BIGINT] - [4]
2014-07-04 15:06:41,338 [主] [ - ] TRACE hibernate.type.descriptor.sql.BasicBinder - 绑定参数[7]为[INTEGER] - [1]
2014-07-04 15:06:41,342 [main] [ - ] DEBUG org.hibernate.SQL -
/ * delete on电子对多com.ia.domain.Provider.contracts * / update
contract
set
provider_id = null
其中
provider_id =?
Hibernate:
/ *删除一对多的com.ia.domain.Provider.contracts * / update
合约
set
provider_id = null
其中
provider_id =?
2014-07-04 15:06:41,344 [main] [ - ] TRACE hibernate.type.descriptor.sql.BasicBinder - 绑定参数[1]为[BIGINT] - [4]


解决方案

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



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

更新使用JPA2的EclipseLink 2.5.1似乎没有此问题



在第2.9节实体关系中,JPA 2.1规范说:
如果实体正在成为孤儿是一个分离的,新的或被删除的实体,orphanRemoval的语义不适用。



我不知道你的相关实体是否被分离,但如果是的话,那么这不是一个错误:)


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.

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

@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.

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.

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.

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

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?

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]

解决方案

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

Probably the Hibernate documentation is lacking in this little detail.

update EclipseLink 2.5.1 with JPA2 does not seem to have this issue

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."

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

这篇关于JPA 2 /休眠孤儿删除仍然不能与@OneToMany一起工作?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆