java Hibernate - 一对多关系和 orphanRemoval 级联
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3204252/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Hibernate - One to many relationship and orphanRemoval cascade
提问by Cedric Thiebault
I have a basic one to many relation parent / child like in the chapter 21 of Hibernate references book.
The cascade is only from child to parent (persist cascade only because I don't want to delete the parent if I delete a child).
When I add a child to the parent and I save the child, I have a TransientObjectException...
我有一个基本的一对多关系父/子,就像 Hibernate 参考书的第 21 章一样。
级联仅从子级到父级(持久级联只是因为我不想在删除子级时删除父级)。
当我将一个孩子添加到父母并保存孩子时,我有一个 TransientObjectException ......
@Entity
public class Parent implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@OneToMany(mappedBy = "parent", orphanRemoval = true)
private List<Child> childs;
public List<Child> getChilds() {
return childs;
}
public void setChilds(List<Child> childs) {
this.childs = childs;
}
public void addChild(Child child) {
if (childs == null) childs = new ArrayList<Child>();
if (childs.add(child)) child.setParent(this);
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
}
@Entity
public class Child implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@ManyToOne(optional = false)
@Cascade( { PERSIST, MERGE, REFRESH, SAVE_UPDATE, REPLICATE, LOCK, DETACH })
private Parent parent;
public Parent getParent() {
return parent;
}
public void setParent(Parent parent) {
this.parent = parent;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
}
@Test
public void test() {
Parent parent = new Parent();
Child child = new Child();
parent.addChild(child);
genericDao.saveOrUpdate(child);
}
But on the saveOrUpdate, I have this exception:
但是在 saveOrUpdate 上,我有这个例外:
org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: Child
at org.hibernate.engine.ForeignKeys.getEntityIdentifierIfNotUnsaved(ForeignKeys.java:244)
at org.hibernate.collection.AbstractPersistentCollection.getOrphans(AbstractPersistentCollection.java:911)
at org.hibernate.collection.PersistentBag.getOrphans(PersistentBag.java:143)
at org.hibernate.engine.CollectionEntry.getOrphans(CollectionEntry.java:373)
at org.hibernate.engine.Cascade.deleteOrphans(Cascade.java:471)
at org.hibernate.engine.Cascade.cascadeCollectionElements(Cascade.java:455)
at org.hibernate.engine.Cascade.cascadeCollection(Cascade.java:362)
at org.hibernate.engine.Cascade.cascadeAssociation(Cascade.java:338)
at org.hibernate.engine.Cascade.cascadeProperty(Cascade.java:204)
at org.hibernate.engine.Cascade.cascade(Cascade.java:161)
at org.hibernate.event.def.AbstractSaveEventListener.cascadeAfterSave(AbstractSaveEventListener.java:476)
at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:354)
at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:204)
at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:130)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:210)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:195)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.performSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:117)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:93)
at org.hibernate.impl.SessionImpl.fireSaveOrUpdate(SessionImpl.java:677)
at org.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:669)
at org.hibernate.engine.CascadingAction.cascade(CascadingAction.java:252)
at org.hibernate.engine.Cascade.cascadeToOne(Cascade.java:392)
at org.hibernate.engine.Cascade.cascadeAssociation(Cascade.java:335)
at org.hibernate.engine.Cascade.cascadeProperty(Cascade.java:204)
at org.hibernate.engine.Cascade.cascade(Cascade.java:161)
at org.hibernate.event.def.AbstractSaveEventListener.cascadeBeforeSave(AbstractSaveEventListener.java:451)
at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:288)
at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:204)
at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:130)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:210)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:195)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.performSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:117)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:93)
at org.hibernate.impl.SessionImpl.fireSaveOrUpdate(SessionImpl.java:677)
at org.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:669)
at org.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:665)
I really don't understand because saving the Child should save the Parent via the cascade... Any ideas ?
我真的不明白,因为拯救孩子应该通过级联来拯救父母......有什么想法吗?
UPDATE 1
The problem seems to be related to "orphanRemoval" because if I comment it on the parent:
更新 1
该问题似乎与“orphanRemoval”有关,因为如果我对父级发表评论:
@OneToMany(mappedBy = "parent" /*, orphanRemoval = true */)
private List<Child> childs;
It works!
It save the child, then the parent.
But I really need the orphan to be deleted via the cascade when I remove a child from its parent.
有用!
它先救孩子,再救父母。
但是当我从父级中删除一个孩子时,我真的需要通过级联删除孤儿。
UPDATE 2
I've created a JIRA issue:
http://opensource.atlassian.com/projects/hibernate/browse/HHH-5364
更新 2
我创建了一个 JIRA 问题:http:
//opensource.atlassian.com/projects/hibernate/browse/HHH-5364
UPDATE 3
It seems to be fixed :-)
http://opensource.atlassian.com/projects/hibernate/browse/HHH-2269
更新 3
似乎已修复 :-)
http://opensource.atlassian.com/projects/hibernate/browse/HHH-2269
采纳答案by Cedric Thiebault
It was an issue in Hibernate and it is now fixed:
这是 Hibernate 中的一个问题,现在已修复:
http://opensource.atlassian.com/projects/hibernate/browse/HHH-2269
http://opensource.atlassian.com/projects/hibernate/browse/HHH-2269
回答by Mikeb
Basically you are violating a constraint. The row in the db that corresponds to the parent doesn't exist, so there is no foreign key relationship that the child can use to refer to the parent. Add a call to saveOrUpdate on the parent before doing do for the child.
基本上你违反了约束。db 中与父级对应的行不存在,因此没有子级可以用来引用父级的外键关系。在为孩子做 do 之前,在父母上添加对 saveOrUpdate 的调用。
(edit) I missed your comment about cascade before the reformatting. My recollection is that cascade doesn't work upstream that way; you would still need to save the parent first.
(编辑)我错过了您在重新格式化之前关于级联的评论。我的回忆是,级联在上游不会那样工作;您仍然需要先保存父级。

