web-dev-qa-db-ja.com

Hibernate:OneToManyはカスケードによって子を保存します

クラスParentにはリストListがあります。親が保存されると、追加または変更された子はhibernateによって保存/更新されます。

私はこれについて多くの説明を見つけましたが、私はそれを機能させません。

Parent.class try A

@Entity
public class Parent {
// id and other attributes
@OneToMany(mappedBy = "parent")
@org.hibernate.annotations.Cascade(org.hibernate.annotations.CascadeType.ALL)
protected List<child> children;

Parent.class try B

@Entity
public class Parent {
// id and other attributes
  @OneToMany(mappedBy = "parent", cascade = { javax.persistence.CascadeType.ALL },
 orphanRemoval = true)
 @org.hibernate.annotations.Cascade({ 
 org.hibernate.annotations.CascadeType.PERSIST,
 org.hibernate.annotations.CascadeType.MERGE,
 org.hibernate.annotations.CascadeType.REFRESH,
 org.hibernate.annotations.CascadeType.SAVE_UPDATE,
 org.hibernate.annotations.CascadeType.REPLICATE,
 org.hibernate.annotations.CascadeType.LOCK,
 org.hibernate.annotations.CascadeType.DETACH })
protected List<child> children;

子は新しい親に追加されます。その後、両方が保存されます

sessionFactory.getCurrentSession().saveOrUpdate(parent);

ただし、フラッシュすると、次のエラーが表示されます。

org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: de.pockettaxi.backend.model.ride.RideSingle
at org.hibernate.engine.ForeignKeys.getEntityIdentifierIfNotUnsaved(ForeignKeys.Java:243)
at org.hibernate.type.EntityType.getIdentifier(EntityType.Java:456)
at org.hibernate.type.ManyToOneType.isDirty(ManyToOneType.Java:265)
at org.hibernate.type.ManyToOneType.isDirty(ManyToOneType.Java:275)
at org.hibernate.type.TypeHelper.findDirty(TypeHelper.Java:295)
at org.hibernate.persister.entity.AbstractEntityPersister.findDirty(AbstractEntityPersister.Java:3378)
at org.hibernate.event.def.DefaultFlushEntityEventListener.dirtyCheck(DefaultFlushEntityEventListener.Java:520)
at org.hibernate.event.def.DefaultFlushEntityEventListener.isUpdateNecessary(DefaultFlushEntityEventListener.Java:230)
at org.hibernate.event.def.DefaultFlushEntityEventListener.onFlushEntity(DefaultFlushEntityEventListener.Java:154)
at org.hibernate.event.def.AbstractFlushingEventListener.flushEntities(AbstractFlushingEventListener.Java:219)
at org.hibernate.event.def.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.Java:99)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.Java:50)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.Java:1216)

誰かが私の間違いを見ていますか?

本当にありがとうございます!!

19
Steve Eastwood

最初のコメントの質問に答えれば、このような状況になるでしょう。

  • あなたはすでに永続化された親を持っています
  • まだ永続化されていない新しい子オブジェクトがあります
  • 子を親に追加し、saveOrUpdateを実行します

その場合、休止状態は単に保存または更新を子にカスケードしますが、まだ永続的ではないため、保存または更新することはできません。そして今、Hibernateは単に「非永続エンティティを更新できない」と言っています

1つの文で:Hibernateはカスケードに発行されたもののみをカスケードします。この場合、"SAVE_UPDATE"を発行します。これは、カスケードされてさらに子になります。 Hibernateが賢く、ここで子供たちのために持続するように切り替わると期待していたと思います。しかし、これはここでHibernateがどのように機能するかではなく、以前にも同様の状況に遭遇しました。少し混乱しますが、一度カスケードがどのように機能するかを知っていれば、そのような状況がわかります。

15
Markus

Parent.class try Aはすでに正しいようです。ただし、親を保存しながら子をカスケードするには、所有者側にカスケードを配置する必要があります(1対多では、外部キーを持つエンティティです)。

これを試して

@Entity
public class Parent {
    @OneToMany(mappedBy = "parent")
    protected List<Child> children;
}

そしてあなたのChild.classで

@Entity
public class Child {
    @ManyToOne
    @Cascade(value={org.hibernate.annotations.CascadeType.ALL})
    @JoinColumn(name="PARENT_ID")
    protected Parent parent;
}
13
Joshua H

新しい結合(子)エンティティを含むエンティティを一緒に挿入する方法が必要でした。それを行う1つの方法は、アクションを分離することです(たとえば、結合されたエンティティを最初に保存し、次にメインエンティティを保存する)。ただし、Hibernateは、新しい結合されたエンティティで新しいエンティティの挿入をサポートします。方法の例を参照してください: カスケードでOneToManyの子を挿入する方法

6
Ilanh

これを試して:

@Entity
@Table(name = "TABLE_PARENT")
public class Parent{
    @OneToMany(mappedBy="parent", cascade=CascadeType.PERSIST)
    private List<Child> children;
}

@Entity
@Table(name = "TABLE_CHILD")
public class Child{
    @ManyToOne(fetch=FetchType.LAZY)
    @JoinColumn(name="PARENT_ID")
    private Parent parent;
}

使用法

public void save(){
  Parent parent = new Parent();
  List<Child> children = new ArrayList<>();
  Child child = new Child();
  child.setParent(parent);
  children.add(child);
  parent.setChildren(children);

  parentRepository.save(parent);
}

注:子オブジェクトに親を設定することを忘れないでください。そうしないと、TABLE_CHILD.PARENT_ID null /空になります