孤儿仍然在数据库中,即使orphanRemoval = true在一对多关系(JPA / Hibernate) [英] Orphans remain in database even with orphanRemoval=true on one-to-many relationship (JPA/Hibernate)

查看:1254
本文介绍了孤儿仍然在数据库中,即使orphanRemoval = true在一对多关系(JPA / Hibernate)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

  @Entity 
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@Table(name =company_policies)
@DiscriminatorColumn(name = rule_name)
public abstract class AbstractPolicyRule implements Serializable {

@Transient
private static final long serialVersionUID = 1L;

@Id
@GeneratedValue
私人长ID;
私有字符串值;

...
}

_

  @Entity 
public class类实现Serializable {

@Transient
private static final long serialVersionUID = 1L;

@Id
@GeneratedValue
私人长ID;
@Column(name =category_name)
私人字符串名称;

@OneToMany(fetch = FetchType.EAGER,cascade = {CascadeType.ALL},orphanRemoval = true)
@JoinColumn(name =category_policy_id,referencedColumnName =id)
private Set< AbstractPolicyRule> activePolicyRules;

...
}

现有的activePolicyRules将其category_policy_id在数据库中设置为null,并插入新的。我想要将原始的删除。

我认为加入orphanRemoval = true会做到这一点,但事实并非如此。我在其中看到的其他问题似乎具有双向关系,并将父级设置为null可解决此问题,但这不是双向关系。



任何建议?



使用Hibernate 3.5.3



编辑:
只有当现有的AbstractPolicyRule存在于数据库中,我从列表中删除它,然后再次保存类别。

  [DEBUG]找到的集合:[domain.category。 Category.activePolicyRules#1]是:
[< unreferenced>](初始化)
[DEBUG]刷新:0插入,2更新,0删除2个对象
[DEBUG]刷新:1个(重新创建),0个更新,1个删除到1个集合
...
[DEBUG]删除集合:[domain.category.Category2.activePolicyRules#1]
[DEBUG]即将打开PreparedStatement(打开PreparedStatements:0,全局为0)
[DEBUG] update company_policies set category_policy_id = null where category_policy_id =?
[DEBUG]完成删除集合

还尝试了一个连接表,因为Hibernate文档不鼓励以前的方式:

  @Entity 
public class类实现Serializable {

@Transient
private static final long serialVersionUID = 1L;

@Id
@GeneratedValue
私人长ID;
@Column(name =category_name)
私人字符串名称;

@OneToMany(fetch = FetchType.EAGER,cascade = {CascadeType.ALL},orphanRemoval = true)
@JoinTable(name =policy_rule_mapping,
joinColumns = @JoinColumn (name =category_id),
inverseJoinColumns = @JoinColumn(name =rule_id))
private Set< AbstractPolicyRule> activePolicyRules;

...
}

这有同样的问题。映射表中的行将被删除,但AbstractPolicyRule仍包含已删除的项目。

解决方案

c> orphanRemoval = true 与一个单向一对多关联没有任何问题。



实际上,我测试了您的代码和以下内容方案( AbstractPolicyRule 正确地)执行等于 / hashCode / p>

  Category category = new Category(); 
AbstractPolicyRule policyRule1 = new AbstractPolicyRule(foo);

category.addToActivePolicyRules(policyRule1);
em.persist(category);
em.flush();

assertNotNull(category.getId());
assertNotNull(category.getActivePolicyRules());
assertEquals(1,category.getActivePolicyRules()。size());

category.removeFromActivePolicyRules(policyRule1);
category.addToActivePolicyRules(new AbstractPolicyRule(bar));
// category = em.merge(category); //可以使用或不使用
em.flush();
assertEquals(1,category.getActivePolicyRules()。size());

正常工作。在生成的跟踪下面:

 
22:54:30.817 [main] DEBUG org.hibernate.SQL - 插入类别(id,category_name)值(空,?)
Hibernate:插入类(id,category_name)值(空,?)
22:54:30.824 [main] TRACE org.hibernate.type.StringType - 参数:1
22:54:30.844 [main] DEBUG ohid.IdentifierGeneratorHelper - 本地生成的标识:1
...
22:54:30.872 [main] DEBUG org.hibernate。 SQL插入AbstractPolicyRule(id,name)values(null,?)
Hibernate:插入AbstractPolicyRule(id,name)values(null,?)
22:54:30.873 [main] TRACE org .hibernate.type.StringType - 将'foo'绑定到参数:1
22:54:30.874 [main] DEBUG ohid.IdentifierGeneratorHelper - 本地生成的标识:1
...
22 :54:30.924 [main] DEBUG org.hibernate.SQL - update AbstractPolicyRule set category_policy_id =?其中id =?
Hibernate:更新AbstractPolicyRule set category_policy_id =?其中id =?
22:54:30.927 [main] TRACE org.hibernate.type.LongType - 绑定'1'参数:1
22:54:30.928 [main] TRACE org.hibernate.type.LongType - 绑定'1'到参数:2
22:54:30.929 [main] DEBUG ohpcAbstractCollectionPersister - 完成插入集合:插入1行
22:54:30.929 [main] DEBUG org.hibernate.jdbc。 AbstractBatcher - 执行批量大小:1
...
22:54:30.945 [main] DEBUG org.hibernate.SQL - 插入AbstractPolicyRule(id,name)values(null,?)
Hibernate:插入到AbstractPolicyRule(id,name)values(null,?)
22:54:30.948 [main] TRACE org.hibernate.type.StringType - 绑定bar到参数:1
22:54:30.948 [main] DEBUG org.hibernate.SQL - 更新AbstractPolicyRule set category_policy_id =更新AbstractPolicyRule set_type_policy_id = null where category_policy_id =?和id =?
Hibernate:update AbstractPolicyRule set category_policy_id = null where category_policy_id =?和id =?
22:54:30.991 [main] TRACE org.hibernate.type.LongType - 将参数绑定为'1':1
22:54:30.992 [main] TRACE org.hibernate.type.LongType - 绑定'1'参数:2
22:54:30.993 [main] DEBUG ohpcAbstractCollectionPersister - 完成删除集合行:1删除
22:54:30.993 [main] DEBUG ohpcAbstractCollectionPersister - 插入集合:[com.stackoverflow.q3304092.Category.activePolicyRules#1]
22:54:30.994 [main] DEBUG org.hibernate.jdbc.AbstractBatcher - 执行批处理大小:1
...
22:54:30.996 [main] DEBUG org.hibernate.SQL - update AbstractPolicyRule set category_policy_id =?其中id =?
Hibernate:更新AbstractPolicyRule set category_policy_id =?其中id =?
22:54:30.997 [main] TRACE org.hibernate.type.LongType - 绑定参数为'1':1
22:54:30.998 [main] TRACE org.hibernate.type.LongType - 绑定'2'到参数:2
22:54:31.002 [main] DEBUG ohpcAbstractCollectionPersister - 完成插入行:1插入
...
22:54:31.015 [main] DEBUG org.hibernate.SQL - 从AbstractPolicyRule中删除,其中id =?
Hibernate:从AbstractPolicyRule中删除,其中id =?
22:54:31.017 [main] TRACE org.hibernate.type.LongType - 将参数绑定为'1':1

第一条政策规则被删除。



如果这并不代表您在做什么,那么您应该提供更多代码。



更新:回答OP的评论...


哇将saveOrUpdate调用更改为合并,现在它正在适当地删除。你有什么洞察力,为什么这是?


只是一个猜测:因为 orphanRemoval 是一个JPA的东西,我不知道是否 saveOrUpdate 会适当地处理它(实际上,我以为你使用 EntityManager API,因为你提到过JPA)。


@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@Table(name = "company_policies")
@DiscriminatorColumn(name = "rule_name")
public abstract class AbstractPolicyRule implements Serializable {

  @Transient
  private static final long serialVersionUID = 1L;

  @Id
  @GeneratedValue
  private Long id;
  private String value;

  ...
}

_

@Entity
public class Category implements Serializable {

  @Transient
  private static final long serialVersionUID = 1L;

  @Id
  @GeneratedValue
  private Long id;
  @Column(name = "category_name")
  private String name;

  @OneToMany(fetch = FetchType.EAGER, cascade = { CascadeType.ALL }, orphanRemoval = true)
  @JoinColumn(name = "category_policy_id", referencedColumnName = "id")
  private Set<AbstractPolicyRule> activePolicyRules;

  ...
}

When this Set is updated the existing activePolicyRules have their category_policy_id set to null in the database and new ones are inserted. I'd like for the original ones to be deleted.

I thought adding the orphanRemoval = true would do that but it's not. Other questions I've seen on this appear to have bi-directional relationships and setting the parent to null solves it, but this is not a bi-directional relationship.

Any suggestions?

Using Hibernate 3.5.3

Edit: This only happens when an existing AbstractPolicyRule exists in the database, I remove it from the list and then save the Category again. It's foreign key, category_policy_id, is set to null instead of being deleted.

[DEBUG] Collection found: [domain.category.Category.activePolicyRules#1], was: 
[<unreferenced>] (initialized)
[DEBUG] Flushed: 0 insertions, 2 updates, 0 deletions to 2 objects
[DEBUG] Flushed: 1 (re)creations, 0 updates, 1 removals to 1 collections
...
[DEBUG] Deleting collection: [domain.category.Category2.activePolicyRules#1]
[DEBUG] about to open PreparedStatement (open PreparedStatements: 0, globally: 0)
[DEBUG] update company_policies set category_policy_id=null where category_policy_id=?
[DEBUG] done deleting collection

Also tried a join table since the Hibernate documentation discourages the previous way:

@Entity
public class Category implements Serializable {

  @Transient
  private static final long serialVersionUID = 1L;

  @Id
  @GeneratedValue
  private Long id;
  @Column(name = "category_name")
  private String name;

  @OneToMany(fetch = FetchType.EAGER, cascade = { CascadeType.ALL }, orphanRemoval = true)
  @JoinTable(name = "policy_rule_mapping", 
    joinColumns = @JoinColumn(name = "category_id"), 
    inverseJoinColumns = @JoinColumn(name = "rule_id"))
  private Set<AbstractPolicyRule> activePolicyRules;

  ...
}

This has the same issue. The row in the mapping table is deleted but the AbstractPolicyRule still contains the removed item.

解决方案

I'm using orphanRemoval=true with an unidirectional One-to-Many association without any problem.

And actually, I tested your code and the following scenario (AbstractPolicyRule implementing equals/hashCode correctly):

Category category = new Category();
AbstractPolicyRule policyRule1 = new AbstractPolicyRule("foo");

category.addToActivePolicyRules(policyRule1);
em.persist(category);
em.flush();

assertNotNull(category.getId());
assertNotNull(category.getActivePolicyRules());
assertEquals(1, category.getActivePolicyRules().size());

category.removeFromActivePolicyRules(policyRule1);
category.addToActivePolicyRules(new AbstractPolicyRule("bar"));
// category = em.merge(category); // works with or without
em.flush();
assertEquals(1, category.getActivePolicyRules().size());

just works as expected. Below the generated traces:

22:54:30.817 [main] DEBUG org.hibernate.SQL - insert into Category (id, category_name) values (null, ?)
Hibernate: insert into Category (id, category_name) values (null, ?)
22:54:30.824 [main] TRACE org.hibernate.type.StringType - binding null to parameter: 1
22:54:30.844 [main] DEBUG o.h.id.IdentifierGeneratorHelper - Natively generated identity: 1
...
22:54:30.872 [main] DEBUG org.hibernate.SQL - insert into AbstractPolicyRule (id, name) values (null, ?)
Hibernate: insert into AbstractPolicyRule (id, name) values (null, ?)
22:54:30.873 [main] TRACE org.hibernate.type.StringType - binding 'foo' to parameter: 1
22:54:30.874 [main] DEBUG o.h.id.IdentifierGeneratorHelper - Natively generated identity: 1
...
22:54:30.924 [main] DEBUG org.hibernate.SQL - update AbstractPolicyRule set category_policy_id=? where id=?
Hibernate: update AbstractPolicyRule set category_policy_id=? where id=?
22:54:30.927 [main] TRACE org.hibernate.type.LongType - binding '1' to parameter: 1
22:54:30.928 [main] TRACE org.hibernate.type.LongType - binding '1' to parameter: 2
22:54:30.929 [main] DEBUG o.h.p.c.AbstractCollectionPersister - done inserting collection: 1 rows inserted
22:54:30.929 [main] DEBUG org.hibernate.jdbc.AbstractBatcher - Executing batch size: 1
...
22:54:30.945 [main] DEBUG org.hibernate.SQL - insert into AbstractPolicyRule (id, name) values (null, ?)
Hibernate: insert into AbstractPolicyRule (id, name) values (null, ?)
22:54:30.948 [main] TRACE org.hibernate.type.StringType - binding 'bar' to parameter: 1
22:54:30.948 [main] DEBUG o.h.id.IdentifierGeneratorHelper - Natively generated identity: 2
...
22:54:30.990 [main] DEBUG org.hibernate.SQL - update AbstractPolicyRule set category_policy_id=null where category_policy_id=? and id=?
Hibernate: update AbstractPolicyRule set category_policy_id=null where category_policy_id=? and id=?
22:54:30.991 [main] TRACE org.hibernate.type.LongType - binding '1' to parameter: 1
22:54:30.992 [main] TRACE org.hibernate.type.LongType - binding '1' to parameter: 2
22:54:30.993 [main] DEBUG o.h.p.c.AbstractCollectionPersister - done deleting collection rows: 1 deleted
22:54:30.993 [main] DEBUG o.h.p.c.AbstractCollectionPersister - Inserting rows of collection: [com.stackoverflow.q3304092.Category.activePolicyRules#1]
22:54:30.994 [main] DEBUG org.hibernate.jdbc.AbstractBatcher - Executing batch size: 1
...
22:54:30.996 [main] DEBUG org.hibernate.SQL - update AbstractPolicyRule set category_policy_id=? where id=?
Hibernate: update AbstractPolicyRule set category_policy_id=? where id=?
22:54:30.997 [main] TRACE org.hibernate.type.LongType - binding '1' to parameter: 1
22:54:30.998 [main] TRACE org.hibernate.type.LongType - binding '2' to parameter: 2
22:54:31.002 [main] DEBUG o.h.p.c.AbstractCollectionPersister - done inserting rows: 1 inserted
...
22:54:31.015 [main] DEBUG org.hibernate.SQL - delete from AbstractPolicyRule where id=?
Hibernate: delete from AbstractPolicyRule where id=?
22:54:31.017 [main] TRACE org.hibernate.type.LongType - binding '1' to parameter: 1

The first policy rule gets deleted.

If this is not representative of what you're doing, you should maybe provide more code.

Update: Answering a comment from the OP...

Wow I just changed the saveOrUpdate call to merge and now it's removing appropriately. You have any insight why that is?

Just a guess: since orphanRemoval is a JPA thing, I wonder if saveOrUpdate will deal appropriately with it (actually, I thought you were using the EntityManager API since you mentioned JPA).

这篇关于孤儿仍然在数据库中,即使orphanRemoval = true在一对多关系(JPA / Hibernate)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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