Hibernate使用OrphanRemoval触发约束冲突

我在使用JPA / Hibernate(3.5.3)设置时遇到麻烦,在这里我有一个实体,即“ Account”类,该类具有子实体列表,“

Contact”实例。我试图能够将Contact的实例添加/删除到Account的List 属性中。

将新实例添加到集合中并调用saveOrUpdate(account)可以保留所有可爱的东西。如果我然后选择从列表中删除该联系人并再次调用saveOrUpdate,则SQL

Hibernate似乎会涉及将account_id列设置为null,这违反了数据库约束。

我究竟做错了什么?

下面的代码显然是简化的摘要,但是我认为它涵盖了问题,因为我在不同的代码中看到了相同的结果,这实际上就是这个简单的问题。

SQL:

CREATE TABLE account ( 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> 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 = ?

编辑#1:

可能这实际上是一个错误

http://opensource.atlassian.com/projects/hibernate/browse/HHH-5091

编辑#2:

我有一个似乎有效的解决方案,但涉及使用Hibernate API

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;

}

由于不推荐使用Hibernate CascadeType.DELETE_ORPHAN,因此我不得不假定它已被JPA2版本所取代,但是该实现缺少一些东西。

回答:

一些说明:

  • 由于您具有双向关联,因此需要添加一个mappedBy属性来声明关联的拥有方。
  • 同样不要忘记,在使用双向关联时,您需要管理链接的两端,我建议为此使用防御性方法(如下所示)。
  • 你必须实现equalshashCodeContact

因此,在中Account,像这样修改映射:

@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,重要的部分是该@ManyToOne字段应将optional标志设置为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被删除,按预期方式。使用Hibernate 3.5.3-Final测试。

以上是 Hibernate使用OrphanRemoval触发约束冲突 的全部内容, 来源链接: utcz.com/qa/400339.html

回到顶部