即使在一对多关系上设置了 orphanRemoval=true ,孤儿仍保留在数据库中(JPA/Hibernate)

发布于 2024-09-10 12:57:34 字数 2432 浏览 2 评论 0原文

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

  ...
}

当此集合更新时,现有的 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: 
[<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 仍包含已删除的项目。

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

分开我的手 2024-09-17 12:57:34

我使用 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 - 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

第一个策略规则被删除。

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

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

哇,我刚刚将 saveOrUpdate 调用更改为合并,现在它正在适当删除。您知道这是为什么吗?

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

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

公布 2024-09-17 12:57:34

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

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

First make sure your classes implement the hashCode() and equals() methods, so that hibernate knows that exactly these items are removed from the set.

Then try defining the hibernate @Cascade annotation, specifying the delete-orphan cascade type there and observer whether the same happens. If it works the way you want it - report a bug in hibernate and temporarily use the proprietary annotation. Otherwise - update the question with the details

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文