【问题标题】:Hibernate - One to many relationship and orphanRemoval cascadeHibernate - 一对多关系和 orphanRemoval 级联
【发布时间】:2011-03-13 08:48:13
【问题描述】:

我有一个基本的一对多关系父/子,就像在 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);
}

但是在 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$5.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)

我真的不明白,因为拯救孩子应该通过级联拯救父母...... 有什么想法吗?

更新 1
这个问题似乎与“orphanRemoval”有关,因为如果我在父级上发表评论:

@OneToMany(mappedBy = "parent" /*, orphanRemoval = true */)
private List<Child> childs;

有效!
它拯救了孩子,然后是父母。
但是当我从父级中删除一个孩子时,我真的需要通过级联删除孤儿。

更新 2
我创建了一个 JIRA 问题:
http://opensource.atlassian.com/projects/hibernate/browse/HHH-5364

更新 3
它似乎已修复:-)
http://opensource.atlassian.com/projects/hibernate/browse/HHH-2269

【问题讨论】:

  • 欢迎来到 Stack Overflow!将来使用带有 0 和 1 的按钮来正确格式化您的代码(我已为您格式化)。
  • 谢谢...我们同时做到了 ;-)
  • 如果先救父母再救孩子会怎样?
  • 它可以工作,但我不能在我的应用程序中这样做。孩子们在其他实体中使用并通过级联保存......这就是为什么我想在孩子们被保存时也保存他们的父母。

标签: java hibernate one-to-many cascade orphan


【解决方案1】:

这是 Hibernate 中的一个问题,现在已修复:

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

【讨论】:

    【解决方案2】:

    基本上你违反了一个约束。 db 中对应于 parent 的行不存在,因此不存在 child 可以用来引用 parent 的外键关系。在为孩子做之前,在父母上添加对 saveOrUpdate 的调用。

    (编辑)我错过了您在重新格式化之前对级联的评论。我的回忆是级联不能以这种方式在上游工作。您仍然需要先保存父母。

    【讨论】:

    • 好的,但是 saveOrUpdate 在单个事务中执行,所以它首先保存子级,然后级联应该创建父级(并更新子外键),最后刷新到 DB 并且仅在此验证约束的那一刻......没有?
    • 您是否尝试将 'inverse=true' 添加到父映射?我认为这行不通,但 Hibernate 让我感到惊讶。
    • 我使用的不是xml配置而是注解。 @OneToMany(mappedBy = "parent") 也一样。
    • 看来我的问题来自 orphanRemoval... 我刚刚更新了我的帖子。
    • @Cedric:看起来像 Hibernate 中的一个错误。
    猜你喜欢
    • 2016-05-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-05
    • 2022-10-07
    • 2015-01-26
    • 2018-10-16
    • 2015-03-24
    相关资源
    最近更新 更多