Hibernate使用orphanRemoval触发约束违规 [英] Hibernate triggering constraint violations using orphanRemoval
问题描述
我在JPA / Hibernate(3.5.3)设置中遇到问题,我有一个实体,一个Account类,它有一个子实体列表Contact实例。我试图将联系人的实例添加/删除到列表<联系人>
在集合中添加一个新实例并调用saveOrUpdate(account)可以保持一切可爱。如果我然后选择从列表中删除联系人并再次调用saveOrUpdate,SQL Hibernate似乎产生涉及将account_id列设置为null,这违反了数据库约束。
我在做什么错了?
下面的代码显然是一个简化的摘要,但我认为它涵盖了问题,因为我在不同的代码中看到了相同的结果,
SQL:
CREATE TABLE帐户(INT account_id);
CREATE TABLE contact(INT contact_id,INT account_id REFERENCES account(account_id));
Java:
@Entity
class Account {
@Id
@Column
public Long id;
@OneToMany(cascade = CascadeType.ALL,orphanRemoval = true)
@JoinColumn(name =account_id)
public List< Contact>联系人;
}
@Entity
class联系人{
@Id
@Column
public Long id;
@ManyToOne(可选= false)
@JoinColumn(name =account_id,nullable = false)
公共账户;
}
帐户帐户=新帐户();
联系人联系人=新联系人();
account.contacts.add(contact);
saveOrUpdate(account);
//一段时间后,像另一个servlet请求一样....
account.contacts.remove(contact);
saveOrUpdate(account);
结果:
UPDATE联系人SET account_id = null在哪里contact_id =?
编辑#1:
因为这实际上是一个错误 有一个似乎可行的解决方案,但涉及到使用Hibernate API 由于Hibernate CascadeType.DELETE_ORPHAN已被弃用,我不得不假设它已经被JPA2版本所取代,但是实现中缺少一些东西。 一些评论: 因此,在 通过这些修改,以下内容可以正常工作: 并将孤立的 I'm having trouble with a JPA/Hibernate (3.5.3) setup, where I have an entity, an "Account" class, which has a list of child entities, "Contact" instances. I'm trying to be able to add/remove instances of Contact into a List<Contact> property of Account. Adding a new instance into the set and calling saveOrUpdate(account) persists everything lovely. If I then choose to remove the contact from the list and again call saveOrUpdate, the SQL Hibernate seems to produce involves setting the account_id column to null, which violates a database constraint. What am I doing wrong? The code below is clearly a simplified abstract but I think it covers the problem as I'm seeing the same results in different code, which really is about this simple. SQL: Java: Result: Edit #1: It might be that this is actually a bug
http://opensource.atlassian.com/projects/hibernate/browse/HHH-5091 Edit #2: I've got a solution that seems to work, but involves using the Hibernate API Since Hibernate CascadeType.DELETE_ORPHAN is deprecated, I'm having to assume that it has been superseded by the JPA2 version, but the implementation is lacking something. Some remarks: So, in In With these modifications, the following just works: And the orphaned 这篇关于Hibernate使用orphanRemoval触发约束违规的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
http://opensource.atlassian。编辑#2:
class Account {
@SuppressWarnings( 弃用)
@OneToMany(cascade = CascadeType.ALL,mappedBy =account)
@Cascade(org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
@JoinColumn(name = account_id,nullable = false)
私人设定<联络人> contacts = new HashSet< Contact>();
}
class联系{
@ManyToOne(可选= false)
@JoinColumn(name =account_id,nullable = false)
私人账户帐户;
$ b
mappedBy
属性来声明自己的一面该协会。
联系人
等于
和 hashCode
/ code>。
Account
映射如下:
@Entity
public class Account {
@Id @GeneratedValue
公开长ID;
@OneToMany(cascade = CascadeType.ALL,mappedBy =account,orphanRemoval = true)
public List< Contact> contacts = new ArrayList< Contact>();
public void addToContacts(Contact contact){
this.contacts.add(contact);
contact.setAccount(this);
}
public void removeFromContacts(Contact contact){
this.contacts.remove(contact);
contact.setAccount(null);
}
// getters,setters
}
<在联系
中,重要的部分是 @ManyToOne
字段应该有可选标记设为
false :
@实体
public class Contact {
@Id @GeneratedValue
public Long id;
@ManyToOne(可选= false)
公共账户;
// getters,setters,equals,hashCode
}
Account account = new Account();
联系人联系人=新联系人();
account.addToContact(contact);
em.persist(account);
em.flush();
assertNotNull(account.getId());
assertNotNull(account.getContacts()。get(0).getId());
assertEquals(1,account.getContacts()。size());
account.removeFromContact(contact);
em.merge(account);
em.flush();
assertEquals(0,account.getContacts()。size());
Contact
删除,如下预期。使用Hibernate 3.5.3-Final进行测试。CREATE TABLE account ( INT account_id );
CREATE TABLE contact ( INT contact_id, INT account_id REFERENCES account (account_id) );
@Entity
class Account {
@Id
@Column
public Long id;
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
@JoinColumn(name = "account_id")
public List<Contact> contacts;
}
@Entity
class Contact {
@Id
@Column
public Long id;
@ManyToOne(optional = false)
@JoinColumn(name = "account_id", nullable = false)
public Account account;
}
Account account = new Account();
Contact contact = new Contact();
account.contacts.add(contact);
saveOrUpdate(account);
// some time later, like another servlet request....
account.contacts.remove(contact);
saveOrUpdate(account);
UPDATE contact SET account_id = null WHERE contact_id = ?
class Account {
@SuppressWarnings("deprecation")
@OneToMany(cascade = CascadeType.ALL, mappedBy = "account")
@Cascade(org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
@JoinColumn(name = "account_id", nullable = false)
private Set<Contact> contacts = new HashSet<Contact>();
}
class Contact {
@ManyToOne(optional = false)
@JoinColumn(name = "account_id", nullable = false)
private Account account;
}
mappedBy
attribute to declare the owning side of the association. equals
and hashCode
on Contact
.Account
, modify the mapping like this:@Entity
public class Account {
@Id @GeneratedValue
public Long id;
@OneToMany(cascade = CascadeType.ALL, mappedBy = "account", orphanRemoval = true)
public List<Contact> contacts = new ArrayList<Contact>();
public void addToContacts(Contact contact) {
this.contacts.add(contact);
contact.setAccount(this);
}
public void removeFromContacts(Contact contact) {
this.contacts.remove(contact);
contact.setAccount(null);
}
// getters, setters
}
Contact
, the important part is that the @ManyToOne
field should have the optional
flag set to false
:@Entity
public class Contact {
@Id @GeneratedValue
public Long id;
@ManyToOne(optional = false)
public Account account;
// getters, setters, equals, hashCode
}
Account account = new Account();
Contact contact = new Contact();
account.addToContact(contact);
em.persist(account);
em.flush();
assertNotNull(account.getId());
assertNotNull(account.getContacts().get(0).getId());
assertEquals(1, account.getContacts().size());
account.removeFromContact(contact);
em.merge(account);
em.flush();
assertEquals(0, account.getContacts().size());
Contact
gets deleted, as expected. Tested with Hibernate 3.5.3-Final.