gpt4 book ai didi

java - Hibernate 使用 orphanRemoval 触发约束违规

转载 作者:太空狗 更新时间:2023-10-29 22:54:39 26 4
gpt4 key购买 nike

我在使用 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 属性来声明关联的拥有方。
  • 另外不要忘记,在使用双向关联时,您需要管理链接的两侧,我建议为此使用防御方法(如下所示)。
  • 并且您必须在Contact 上实现equalshashCode

因此,在 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 进行测试。

关于java - Hibernate 使用 orphanRemoval 触发约束违规,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3068817/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com