java 即使在一对多关系 (JPA/Hibernate) 中 orphanRemoval=true 时,孤儿仍保留在数据库中
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3304092/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Orphans remain in database even with orphanRemoval=true on one-to-many relationship (JPA/Hibernate)
提问by Josh
@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.
当此 Set 更新时,现有的 activePolicyRules 在数据库中将其 category_policy_id 设置为 null 并插入新的。我想删除原来的。
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.
我认为添加 orphanRemoval = true 会做到这一点,但事实并非如此。我在这方面看到的其他问题似乎有双向关系,将父级设置为 null 可以解决它,但这不是双向关系。
Any suggestions?
有什么建议?
Using Hibernate 3.5.3
使用休眠 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.
编辑:这仅在数据库中存在现有 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
Also tried a join table since the Hibernate documentation discourages the previous way:
还尝试了连接表,因为 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;
...
}
This has the same issue. The row in the mapping table is deleted but the AbstractPolicyRule still contains the removed item.
这有同样的问题。映射表中的行已删除,但 AbstractPolicyRule 仍包含已删除的项目。
采纳答案by Pascal Thivent
I'm using orphanRemoval=truewith an unidirectional One-to-Many association without any problem.
我正在使用orphanRemoval=true单向一对多关联,没有任何问题。
And actually, I tested your code and the following scenario (AbstractPolicyRuleimplementing equals/hashCodecorrectly):
实际上,我测试了您的代码和以下场景(正确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());
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...
更新:回答来自 OP 的评论......
Wow I just changed the saveOrUpdate call to merge and now it's removing appropriately. You have any insight why that is?
哇,我刚刚将 saveOrUpdate 调用更改为合并,现在它正在适当地删除。你知道这是为什么吗?
Just a guess: since orphanRemovalis a JPA thing, I wonder if saveOrUpdatewill deal appropriately with it (actually, I thought you were using the EntityManagerAPI since you mentioned JPA).
只是一个猜测:既然orphanRemoval是 JPA 的东西,我想知道是否saveOrUpdate会适当地处理它(实际上,EntityManager因为你提到 JPA ,我以为你正在使用API)。
回答by Bozho
First make sure your classes implement the hashCode()and equals()methods, so that hibernate knows that exactly these items are removed from the set.
首先确保您的类实现了hashCode()和equals()方法,以便 hibernate 知道这些项目已从集合中删除。
Then try defining the hibernate @Cascadeannotation, 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
然后尝试定义 hibernate@Cascade注释,在那里指定 delete-orphan 级联类型并观察是否会发生同样的情况。如果它按您希望的方式工作 - 报告 hibernate 中的错误并暂时使用专有注释。否则 - 用详细信息更新问题

