即使在一对多关系中使用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 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 activePolicyRules; ... } 

更新此Set时,现有的activePolicyRules将其category_policy_id在数据库中设置为null,并插入新的。 我希望删除原来的。

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

有什么建议么?

使用Hibernate 3.5.3

编辑:这只发生在数据库中存在现有的AbstractPolicyRule时,我将其从列表中删除,然后再次保存类别。 它的外键category_policy_id设置为null而不是被删除。

 [DEBUG] Collection found: [domain.category.Category.activePolicyRules#1], was: [] (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 

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

 @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 activePolicyRules; ... } 

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

我使用orphanRemoval=true与单向一对多关联没有任何问题。

实际上,我测试了您的代码和以下场景( AbstractPolicyRule正确实现了equals / hashCode ):

 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()); 

只是按预期工作。 生成的跟踪下面:

 22:54:30.817 [main] DEBUG org.hibernate.SQL  - 插入Category(id,category_name)值(null,?)
 Hibernate:插入Category(id,category_name)值(null,?)
 22:54:30.824 [main] TRACE org.hibernate.type.StringType  - 将null绑定到参数:1
 22:54:30.844 [main] DEBUG ohid.IdentifierGeneratorHelper  - 本机生成的身份:1
 ...
 22:54:30.872 [main] DEBUG org.hibernate.SQL  - 插入AbstractPolicyRule(id,name)值(null,?)
 Hibernate:插入AbstractPolicyRule(id,name)值(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  - 更新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)值(null,?)
 Hibernate:插入AbstractPolicyRule(id,name)值(null,?)
 22:54:30.948 [main] TRACE org.hibernate.type.StringType  - 将'bar'绑定到参数:1
 22:54:30.948 [main] DEBUG ohid.IdentifierGeneratorHelper  - 本机生成的身份:2
 ...
 22:54:30.990 [main] DEBUG org.hibernate.SQL  - 更新AbstractPolicyRule set category_policy_id = null其中category_policy_id =? 和id =?
 Hibernate:更新AbstractPolicyRule set category_policy_id = null其中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  - 更新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调用更改为merge,现在正在适当地删除它。 你有什么见解为什么?

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

首先确保您的类实现了hashCode()equals()方法,以便hibernate知道这些项是从集合中删除的。

然后尝试定义hibernate @Cascade注释,在那里指定delete-orphan级联类型,并观察是否发生相同的情况。 如果它以你想要的方式工作 – 报告hibernate中的错误并暂时使用专有注释。 否则 – 用详细信息更新问题