我有一个Parent实体与ManyToOne关系中的Child实体:
@Entity class Parent {
// ...
@ManyToOne((cascade = {CascadeType.ALL})
private Child child;
// ...
}
Run Code Online (Sandbox Code Playgroud)
该儿童有一个独特的领域:
@Entity class Child {
// ...
@Column(unique = true)
private String name;
// ...
}
Run Code Online (Sandbox Code Playgroud)
当我需要一个新孩子时,我先问ChildDAO:
Child child = childDao.findByName(name);
if(child == null) {
child = new Child(name);
}
Parent parent = new Parent();
parent.setChild(child);
Run Code Online (Sandbox Code Playgroud)
问题是,如果我喜欢上面两次(对于Child有相同的名字),并且只在最后保留Parent,我会得到一个约束异常.这似乎很正常,因为最初在数据库中没有具有指定名称的子项.
问题是,我不确定什么是避免这种情况的最佳方法.
wrs*_*der 10
您正在创建两个非持久性Child实例,new Child()然后将它们放在两个不同的Parent中.当您持久保存Parent对象时,两个新的Child实例中的每一个都将通过级联持久化/插入,每个实例都有不同的实例@Id.然后,对名称的唯一约束会中断.如果您正在使用CascadeType.ALL,那么每次执行此操作时new Child()您可能会获得一个单独的持久对象.
如果您确实希望将两个Child实例视为具有相同ID的单个持久对象,则需要将其单独保留以与持久性上下文/会话关联.随后的调用childDao.findByName将刷新插入并返回刚刚创建的新Child,因此您不会执行new Child()两次.
你得到这个是因为你试图坚持一个已经存在的对象(相同的ID).你的级联可能不会持续它是MERGE/UPDATE/REMOVE/DETACH.避免这种情况的最佳方法是正确设置级联或手动管理级联.基本上说,级联仍然是通常的罪魁祸首.
你可能想要这样的东西:
//SomeService--I assume you create ID's on persist
saveChild(Parent parent, Child child)
{
//Adding manually (using your cascade ALL)
if(child.getId() == null) //I don't exist persist
persistence.persist(child);
else
persistence.merge(child); //I'm already in the DB, don't recreate me
parent.setChild(child);
saveParent(parent); //using a similar "don't duplicate me" approach.
}
Run Code Online (Sandbox Code Playgroud)
如果让框架管理它,那么级联可能会非常令人沮丧,因为如果它是缓存的话,你偶尔会错过更新(特别是在ManyToOne关系中的Collections).如果您没有明确保存父级并允许框架处理级联.一般来说,我允许来自我父母的Cascade.ALL和我孩子们的DELETE/PERSIST级联.我是一个Eclipselink用户,所以我对Hibernate/other的体验有限,我无法谈论缓存.*真的,想一想 - 如果你正在拯救一个孩子,你真的想要保存所有与之相关的对象吗?另外,如果你要加孩子,你不应该通知家长吗?*
在你的情况下,我只需要在我的Dao/Service中使用"saveParent"和"saveChild"方法,以确保缓存正确并且数据库正确以避免头痛.手动管理意味着您将拥有绝对的控制权,您不必依赖级联来完成您的脏工作.在单向方向上他们是太棒了,他们来到"上游"的那一刻你会有一些意想不到的行为.
| 归档时间: |
|
| 查看次数: |
16283 次 |
| 最近记录: |