エンティティを更新しようとすると、次の問題が発生します。
"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 <..>のみをきれいにしようとしました: 問題を「可能」に解決する方法 が機能しませんでした。
アイデアがあれば、教えてください。
ありがとう!
実際、私の問題は、エンティティの等号とハッシュコードに関するものでした。レガシーコードは多くの問題を引き起こす可能性があるため、忘れずにチェックしてください。私がやったことは、削除孤児戦略を維持し、等しいとハッシュコードを修正するだけでした。
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);
}
メソッド:
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);
}
}
休止状態がコレクションに割り当てることを好まなかったというさまざまな場所を読んだとき、最も安全なことは明らかに次のように最終的なものにすることだと思いました。
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として使用する場合は、おそらく動作するセッターが必要です。これは少なくとも機能しているようです。
同じエラーが発生しました。私にとっての問題は、エンティティを保存した後、マップされたコレクションがまだnullであり、エンティティを更新しようとしたときに例外がスローされたことでした。何が助けになったのか:エンティティを保存してから更新し(コレクションがnullでなくなる)、更新を実行します。新しいArrayList()などでコレクションを初期化することもできます。
関係タイプがあります:
hasMany
で宣言されているコレクションをインスタンス化しようとせず、オブジェクトを追加および削除するだけです。
class Parent {
static hasMany = [childs:Child]
}
関係タイプを使用:
ただし、コレクションがnullになる可能性があるのは、プロパティ(リレーションを使用)として宣言され、宣言で初期化されていない場合のみです。
class Parent {
List<Child> childs = []
}
@ 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);
}
}
}
}
TreeSet
を使用しようとしたときにこの問題が発生しました。私はoneToMany
をTreeSet
で初期化しました。
@OneToMany(mappedBy = "question", fetch = FetchType.EAGER, cascade = { CascadeType.ALL }, orphanRemoval=true)
@OrderBy("id")
private Set<WizardAnswer> answers = new TreeSet<WizardAnswer>();
ただし、これにより、上記のquestion
で説明したエラーが発生します。したがって、hibernate
はSortedSet
をサポートしており、上の行を
@OneToMany(mappedBy = "question", fetch = FetchType.EAGER, cascade = { CascadeType.ALL }, orphanRemoval=true)
@OrderBy("id")
private SortedSet<WizardAnswer> answers;
それは魔法のように機能します:) hibernate SortedSet
の詳細は here
このエラーが発生するのは、コレクションのセッターにNULLを渡そうとしたときだけです。これを防ぐために、私のセッターは次のようになります。
public void setSubmittedForms(Set<SubmittedFormEntity> submittedForms) {
if(submittedForms == null) {
this.submittedForms.clear();
}
else {
this.submittedForms = submittedForms;
}
}
@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つは、ロンボクの使用です。
@Builder
-Collections.emptyList()
と言っても.myCollection(new ArrayList());
を保存します
@Singular
-クラスレベルのデフォルトを無視し、クラスフィールドがmyCollection = new ArrayList()
として宣言されていてもフィールドnull
を残します
私の2セントは、同じで2時間を費やしました:)
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"のコレクションは、所有エンティティインスタンスによって参照されなくなりました 。
愚かな答えを追加します。 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
ではなくメイン構造の一部として子を持っていることを意味しました。親への更新は問題を引き起こします。
次の解決策は私のために働いた
//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;
hibernate-enhance-maven-plugin
が原因である可能性があります。 enableLazyInitialization
プロパティを有効にすると、この例外がレイジーコレクションで発生し始めました。 hibernate 5.2.17.Finalを使用しています。
この2つの休止状態の問題に注意してください。
に注意してください
BeanUtils.copyProperties(newInsum, insumOld,"code");
この方法も休止状態を壊します。
JSONポストリクエストでエンティティを更新するときにこれに遭遇しました。子が存在しない場合でも、子に関するデータなしでエンティティを更新すると、エラーが発生しました。追加中
"children": [],
リクエスト本文に問題を解決しました。
新しいコレクションを割り当てる代わりに
public void setChildren(Set<ChildEntity> children) {
this.children = children;
}
すべての要素を
public void setChildren(Set<ChildEntity> children) {
Collections.replaceAll(this.children,children);
}
私の場合は、Spring Bootとはまったく異なりました。私にとっては、コレクションプロパティの設定によるものではありません。
私のテストでは、エンティティを作成しようとしていて、使用されていない別のコレクションでこのエラーが発生していました!
試行錯誤の末、テストメソッドに@Transactional
を追加しただけで解決しました。理由はありません。
私は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);
}