web-dev-qa-db-ja.com

Hibernate-cascade =” all-delete-Orphan”のコレクションは、所有エンティティインスタンスによって参照されなくなりました

エンティティを更新しようとすると、次の問題が発生します。

"A collection with cascade=”all-delete-Orphan” was no longer referenced by the owning entity instance".

親エンティティがあり、いくつかの子エンティティのSet<...>があります。更新しようとすると、このコレクションに設定するすべての参照を取得して設定します。

次のコードは私のマッピングを表しています:

@OneToMany(mappedBy = "parentEntity", fetch = FetchType.EAGER)
@Cascade({ CascadeType.ALL, CascadeType.DELETE_Orphan })
public Set<ChildEntity> getChildren() {
    return this.children;
}

これに応じて、Set <..>のみをきれいにしようとしました: 問題を「可能」に解決する方法 が機能しませんでした。

アイデアがあれば、教えてください。

ありがとう!

179
axcdnt

実際、私の問題は、エンティティの等号とハッシュコードに関するものでした。レガシーコードは多くの問題を引き起こす可能性があるため、忘れずにチェックしてください。私がやったことは、削除孤児戦略を維持し、等しいとハッシュコードを修正するだけでした。

14
axcdnt

SonEntitiesに何かを割り当てるすべての場所を確認します。参照したリンクは、新しいHashSetの作成を明確に示していますが、セットを再割り当てするたびにこのエラーが発生する可能性があります。例えば:

public void setChildren(Set<SonEntity> aSet)
{
    this.sonEntities = aSet; //This will override the set that Hibernate is tracking.
}

通常、コンストラクターでセットを1回だけ「新規」にしたいだけです。リストに何かを追加または削除するときは、新しいリストを割り当てる代わりに、リストの内容を変更する必要があります。

子を追加するには:

public void addChild(SonEntity aSon)
{
    this.sonEntities.add(aSon);
}

子を削除するには:

public void removeChild(SonEntity aSon)
{
    this.sonEntities.remove(aSon);
}
179
brainimus

メソッド:

public void setChildren(Set<SonEntity> aSet) {
    this.sonEntities = aSet;
}

parentEntityがデタッチされた場合、および更新された場合に再び機能します。
[。

public void setChildren(Set<SonEntity> aSet) {
    //this.sonEntities = aSet; //This will override the set that Hibernate is tracking.
    this.sonEntities.clear();
    if (aSet != null) {
        this.sonEntities.addAll(aSet);
    }
}
87
Manu

休止状態がコレクションに割り当てることを好まなかったというさまざまな場所を読んだとき、最も安全なことは明らかに次のように最終的なものにすることだと思いました。

class User {
  private final Set<Role> roles = new HashSet<>();

public void setRoles(Set<Role> roles) {
  this.roles.retainAll(roles);
  this.roles.addAll(roles);
}
}

ただし、これは機能せず、恐ろしい「参照されなくなった」というエラーが表示されます。この場合、実際にはかなり誤解を招きます。

HibernateがsetRolesメソッドを呼び出し、その特別なコレクションクラスをここにインストールする必要があり、コレクションクラスを受け入れないことがわかりました。 setメソッドでコレクションに割り当てないことに関するすべての警告を読んだにもかかわらず、これは長い間困惑していました。

だから私はこれに変更しました:

public class User {
  private Set<Role> roles = null;

  public void setRoles(Set<Role> roles) {
  if (this.roles == null) {
    this.roles = roles;
  } else {
    this.roles.retainAll(roles);
   this.roles.addAll(roles);
  }
}
}

そのため、最初の呼び出しでhibernateはその特別なクラスをインストールし、その後の呼び出しでは、すべてを破壊することなくメソッドを自分で使用できます。クラスをBeanとして使用する場合は、おそらく動作するセッターが必要です。これは少なくとも機能しているようです。

22
user2709454

同じエラーが発生しました。私にとっての問題は、エンティティを保存した後、マップされたコレクションがまだnullであり、エンティティを更新しようとしたときに例外がスローされたことでした。何が助けになったのか:エンティティを保存してから更新し(コレクションがnullでなくなる)、更新を実行します。新しいArrayList()などでコレクションを初期化することもできます。

9
Konsumierer

関係タイプがあります:


hasManyで宣言されているコレクションをインスタンス化しようとせず、オブジェクトを追加および削除するだけです。

class Parent {
    static hasMany = [childs:Child]
}

関係タイプを使用:


ただし、コレクションがnullになる可能性があるのは、プロパティ(リレーションを使用)として宣言され、宣言で初期化されていない場合のみです。

class Parent {
    List<Child> childs = []
}
4
IgniteCoders

@ user2709454アプローチを使用し、少し改善しました。

public class User {
    private Set<Role> roles;

    public void setRoles(Set<Role> roles) {
        if (this.roles == null) {
            this.roles = roles;
        } else if(this.roles != roles) { // not the same instance, in other case we can get ConcurrentModificationException from hibernate AbstractPersistentCollection
            this.roles.clear();
            if(roles != null){
                this.roles.addAll(roles);
            }
        }
    }
}
3
luwojtaszek

TreeSetを使用しようとしたときにこの問題が発生しました。私はoneToManyTreeSetで初期化しました。

@OneToMany(mappedBy = "question", fetch = FetchType.EAGER, cascade = { CascadeType.ALL }, orphanRemoval=true)
@OrderBy("id")
private Set<WizardAnswer> answers = new TreeSet<WizardAnswer>();

ただし、これにより、上記のquestionで説明したエラーが発生します。したがって、hibernateSortedSetをサポートしており、上の行を

@OneToMany(mappedBy = "question", fetch = FetchType.EAGER, cascade = { CascadeType.ALL }, orphanRemoval=true)
@OrderBy("id")
private SortedSet<WizardAnswer> answers;

それは魔法のように機能します:) hibernate SortedSetの詳細は here

3
oak

このエラーが発生するのは、コレクションのセッターにNULLを渡そうとしたときだけです。これを防ぐために、私のセッターは次のようになります。

public void setSubmittedForms(Set<SubmittedFormEntity> submittedForms) {
    if(submittedForms == null) {
        this.submittedForms.clear();
    }
    else {
        this.submittedForms = submittedForms;
    }
}
2
Arlo Guthrie
@OneToMany(mappedBy = 'parent', cascade= CascadeType.ALL, orphanRemoval = true)
List<Child> children = new ArrayList<>()

子オブジェクトの既存のリストに子オブジェクトを追加すると、同じエラーが発生しました。

childService.saveOrUpdate(child);
parent.addToChildren(child);
parentService.saveOrUpdate(parent);

私の問題を解決したのは、child = childService.saveOrUpdate(child);

今、子供も他の詳細で復活し、うまくいきました。

1
Neha Gupta

他の原因の1つは、ロンボクの使用です。

@Builder-Collections.emptyList()と言っても.myCollection(new ArrayList());を保存します

@Singular-クラスレベルのデフォルトを無視し、クラスフィールドがmyCollection = new ArrayList()として宣言されていてもフィールドnullを残します

私の2セントは、同じで2時間を費やしました:)

0
Jan Zyka

parent.setChildren(new ArrayList<>())を設定していたときにA collection with cascade=”all-delete-Orphan” was no longer referenced by the owning entity instanceを取得していました。 parent.getChildren().clear()に変更すると、問題は解決しました。

詳細を確認してください: HibernateException-cascade = "all-delete-Orphan"のコレクションは、所有エンティティインスタンスによって参照されなくなりました

0
Justas

愚かな答えを追加します。 Spring Data Restを使用しています。これはかなり標準的な関係でした。パターンは他の場所で使用されました。

//Parent class
@OneToMany(mappedBy = 'parent', 
           cascade= CascadeType.ALL, orphanRemoval = true)
@LazyCollection(LazyCollectionOption.FALSE)
List<Child> children = new LinkedList<>()


//Child class
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = 'ParentID', updatable = false)
@JsonBackReference
Parent parent

私たちが作成した関係では、子供たちが自分のレポを通じて追加されることが常に意図されていました。まだレポを追加していませんでした。統合テストでは、REST呼び出しを介してエンティティの完全なライフサイクルを実行していたため、リクエスト間でトランザクションが終了しました。子のレポがないということは、jsonが_embeddedではなくメイン構造の一部として子を持っていることを意味しました。親への更新は問題を引き起こします。

0
Snekse

次の解決策は私のために働いた

//Parent class
@OneToMany(mappedBy = 'parent', 
           cascade= CascadeType.ALL, orphanRemoval = true)
@OrderBy(value="ordinal ASC")
List<Child> children = new ArrayList<>()

//Updated setter of children 
public void setChildren(List<Children> children) {
    this.children.addAll(children);
    for (Children child: children)
        child.setParent(this);
}


//Child class
@ManyToOne
@JoinColumn(name="Parent_ID")
private Parent parent;
0
priyanka_rao

hibernate-enhance-maven-pluginが原因である可能性があります。 enableLazyInitializationプロパティを有効にすると、この例外がレイジーコレクションで発生し始めました。 hibernate 5.2.17.Finalを使用しています。

この2つの休止状態の問題に注意してください。

0

に注意してください

BeanUtils.copyProperties(newInsum, insumOld,"code");

この方法も休止状態を壊します。

0

JSONポストリクエストでエンティティを更新するときにこれに遭遇しました。子が存在しない場合でも、子に関するデータなしでエンティティを更新すると、エラーが発生しました。追加中

"children": [],

リクエスト本文に問題を解決しました。

0
co ting

新しいコレクションを割り当てる代わりに

public void setChildren(Set<ChildEntity> children) {
    this.children = children;
}

すべての要素を

public void setChildren(Set<ChildEntity> children) {
    Collections.replaceAll(this.children,children);
}
0
Marcin Szymczak

私の場合は、Spring Bootとはまったく異なりました。私にとっては、コレクションプロパティの設定によるものではありません。

私のテストでは、エンティティを作成しようとしていて、使用されていない別のコレクションでこのエラーが発生していました!

試行錯誤の末、テストメソッドに@Transactionalを追加しただけで解決しました。理由はありません。

0
madz

私はSpring Bootを使用していますが、コレクションを直接上書きしないにもかかわらず、コレクションでこの問題が発生しました。同じコレクションの追加フィールドを custom serializer and deserializer で宣言しているためですデータのよりフロントエンドに優しい表現:

  public List<Attribute> getAttributes() {
    return attributes;
  }

  public void setAttributes(List<Attribute> attributes) {
    this.attributes = attributes;
  }

  @JsonSerialize(using = AttributeSerializer.class)
  public List<Attribute> getAttributesList() {
    return attributes;
  }

  @JsonDeserialize(using = AttributeDeserializer.class)
  public void setAttributesList(List<Attribute> attributes) {
    this.attributes = attributes;
  }

コレクションmyselfを上書きしていなくても、デシリアライゼーションは内部でそれを行い、この問題をすべて同じように引き起こしているようです。解決策は、デシリアライザーに関連付けられているセッターを変更して、リストをクリアし、すべてを追加するのではなく、それを上書きすることでした。

  @JsonDeserialize(using = AttributeDeserializer.class)
  public void setAttributesList(List<Attribute> attributes) {
    this.attributes.clear();
    this.attributes.addAll(attributes);
  }
0
Sofia Paixão