Будьте в спящем режиме - каскад orphanRemoval и Связь "один ко многим"

У меня есть основной многим родитель отношения / ребенок как в главе 21 В спящем режиме ссылочная книга.
Каскад только от ребенка для порождения (сохраните каскад только потому, что я не хочу удалять родителя, если я удаляю дочерний элемент).
Когда я добавляю ребенка к родителю, и я сохраняю ребенка, у меня есть TransientObjectException...

@Entity
public class Parent implements Serializable {

  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  private Long id;

  @OneToMany(mappedBy = "parent", orphanRemoval = true)
  private List childs;

  public List getChilds() {
    return childs;
  }

  public void setChilds(List childs) {
    this.childs = childs;
  }

  public void addChild(Child child) {
    if (childs == null) childs = new ArrayList();
    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 childs;

Работает!
Это сохраняет ребенка, затем родитель.
Но мне действительно нужна висячая строка, которая будет удалена через каскад, когда я удаляю ребенка из его родителя.

ОБНОВЛЕНИЕ 2
Я создал проблему JIRA:
http://opensource.atlassian.com/projects/hibernate/browse/HHH-5364

ОБНОВЛЕНИЕ 3
Это, кажется, фиксируется :-)
http://opensource.atlassian.com/projects/hibernate/browse/HHH-2269

7
задан Cedric Thiebault 21 July 2010 в 14:49
поделиться

1 ответ

По сути, вы нарушаете ограничение. Строка в базе данных, соответствующая родителю, не существует, поэтому нет отношения внешнего ключа, которое ребенок может использовать для ссылки на родителя. Добавьте вызов saveOrUpdate для родителя перед тем, как делать это для ребенка.

(edit) Я пропустил ваш комментарий о каскаде до переформатирования. Я помню, что каскад не работает в этом направлении; вам все равно придется сначала сохранить родительский объект.

0
ответ дан 7 December 2019 в 20:33
поделиться
Другие вопросы по тегам:

Похожие вопросы: