Java 使用孤立删除休眠触发约束冲突
我在JPA/Hibernate(3.5.3)设置中遇到了问题,我有一个实体,一个“Account”类,它有一个子实体列表,“Contact”实例。我正在尝试将联系人的实例添加/删除到Account的列表属性中 在集合中添加一个新实例并调用saveOrUpdate(account)会保持不变。如果我随后选择从列表中删除联系人并再次调用saveOrUpdate,那么SQL Hibernate似乎会将account\u id列设置为null,这违反了数据库约束 我做错了什么 下面的代码显然是一个简化的摘要,但我认为它涵盖了这个问题,因为我在不同的代码中看到了相同的结果,这实际上是关于这个简单的问题 SQL: 爪哇: 编辑#1: 可能这实际上是一个bug 编辑#2: 我有一个解决方案,它似乎可以工作,但涉及到使用HibernateAPIJava 使用孤立删除休眠触发约束冲突,java,hibernate,orm,jpa,jpa-2.0,Java,Hibernate,Orm,Jpa,Jpa 2.0,我在JPA/Hibernate(3.5.3)设置中遇到了问题,我有一个实体,一个“Account”类,它有一个子实体列表,“Contact”实例。我正在尝试将联系人的实例添加/删除到Account的列表属性中 在集合中添加一个新实例并调用saveOrUpdate(account)会保持不变。如果我随后选择从列表中删除联系人并再次调用saveOrUpdate,那么SQL Hibernate似乎会将account\u id列设置为null,这违反了数据库约束 我做错了什么 下面的代码显然是一个简化的
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;
}
类帐户{
@抑制警告(“弃用”)
@OneToMany(cascade=CascadeType.ALL,mappedBy=“account”)
@Cascade(org.hibernate.annotations.CascadeType.DELETE\u孤儿)
@JoinColumn(name=“account\u id”,nullable=false)
private Set contacts=new HashSet();
}
班级联系{
@多通(可选=假)
@JoinColumn(name=“account\u id”,nullable=false)
私人帐户;
}
由于Hibernate CascadeType.DELETE\u ORPHAN已被弃用,我不得不假设它已被JPA2版本取代,但实现中缺少一些东西。一些备注:
- 由于您具有双向关联,因此需要添加
属性来声明关联的拥有方李>mappedBy
- 另外,不要忘记,在处理双向关联时,您需要管理链接的两侧,我建议为此使用防御方法(如下所示)
- 您必须在
上实现联系人
和等于
哈希代码
帐户中
修改映射,如下所示:
@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
}
通过这些修改,以下功能可以正常工作:
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());
而孤立的
联系人
会按预期被删除。使用Hibernate 3.5.3-Final进行测试。我认为是@JoinColumn上的选项nullable=false和@manytone上的选项optional=false,而不是自定义Hibernate级联。即使我添加了nullable和optional标志,它仍然失败,但这一次,当它意识到它已经创建了一个场景,它违反了一个带注释的约束,而不是SQL约束。3.5.3和JPA2似乎仍然存在一些问题,因为我也无法让@ElementCollection表现得很好。将CascadeType设置为ALL将执行所有操作,在我的例子中,您不必显式为DELETE_,我只使用从父级到chhild的单向关系,OrphanRemoving=true,nullable=false这就是它的工作原理。若我删除nullable=false,则在尝试将引用字段更新为null时触发约束冲突失败。如果我删除ophanRemoval,它不会执行任何更新或删除@Cascade(org.hibernate.annotations.CascadeType.DELETE_ORPHAN)不是必需的,似乎在我为使特定于hibernate的API正常工作所做的更改中,我解决了破坏JPA2版本的任何问题。有点尴尬的是,我怀疑是equals/hashCode…您好,先生,我没有使用EntityManager
,我使用的是Session#saveOrUpdate
hibernate-specific,在DB中我有3个孩子,从视图来看,我有2个孩子要更新,我想删除第三个或最后一个,如何处理这种情况?我应该使用Session#get()
还是Session#load()
,来知道要删除哪个元素?
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;
}
@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
}
@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());