14
@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;

  ...
}

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

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

有什么建议么?

使用休眠 3.5.3

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

[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

还尝试了一个连接表,因为 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<AbstractPolicyRule> activePolicyRules;

  ...
}

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

4

2 回答 2

9

我正在使用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 - 插入类别(id,category_name)值(null,?)
Hibernate:插入类别(id,category_name)值(null,?)
22:54:30.824 [main] TRACE org.hibernate.type.StringType - 将 null 绑定到参数:1
22:54:30.844 [main] 调试 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] 调试 ohid.IdentifierGeneratorHelper - 本机生成的身份:1
...
22:54:30.924 [main] 调试 org.hibernate.SQL - 更新 AbstractPolicyRule 集 category_policy_id=? 哪里id=?
Hibernate:更新 AbstractPolicyRule 集 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] 调试 ohpcAbstractCollectionPersister - 完成插入集合:插入 1 行
22:54:30.929 [main] 调试 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] 调试 ohid.IdentifierGeneratorHelper - 本机生成的身份:2
...
22:54:30.990 [main] 调试 org.hibernate.SQL - 更新 AbstractPolicyRule 集 category_policy_id=null where category_policy_id=? 和身份证=?
Hibernate:更新 AbstractPolicyRule 集 category_policy_id=null where category_policy_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] 调试 ohpcAbstractCollectionPersister - 完成删除集合行:1 已删除
22:54:30.993 [main] 调试 ohpcAbstractCollectionPersister - 插入集合行:[com.stackoverflow.q3304092.Category.activePolicyRules#1]
22:54:30.994 [main] 调试 org.hibernate.jdbc.AbstractBatcher - 执行批处理大小:1
...
22:54:30.996 [main] 调试 org.hibernate.SQL - 更新 AbstractPolicyRule 集 category_policy_id=? 哪里id=?
Hibernate:更新 AbstractPolicyRule 集 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] 调试 ohpcAbstractCollectionPersister - 完成插入行:1 个插入
...
22:54:31.015 [main] 调试 org.hibernate.SQL - 从 id=? 的 AbstractPolicyRule 中删除
休眠:从 id=? 的 AbstractPolicyRule 中删除
22:54:31.017 [main] TRACE org.hibernate.type.LongType - 将“1”绑定到参数:1

第一个策略规则被删除。

如果这不能代表您正在做的事情,您可能应该提供更多代码。

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

哇,我刚刚将 saveOrUpdate 调用更改为合并,现在它正在适当地删除。你有什么见解为什么会这样?

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

于 2010-07-21T23:15:11.880 回答
4

首先确保你的类实现了hashCode()andequals()方法,这样 hibernate 就知道这些项目是从集合中删除的。

然后尝试定义休眠@Cascade注释,在那里指定删除孤儿级联类型并观察是否发生同样的情况。如果它以您想要的方式工作 - 报告休眠中的错误并临时使用专有注释。否则 - 使用详细信息更新问题

于 2010-07-21T22:34:20.510 回答