최대 절전 모드-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 <..> 만 청소하려고 시도했습니다. 문제를 "가능한"해결하는 방법 이 작동하지 않았습니다.
아이디어가 있으시면 알려주십시오.
감사!
sonEntities에 무언가를 할당하는 모든 장소를 확인하십시오. 참조한 링크는 새 HashSet 작성을 명확하게 나타내지 만 세트를 다시 지정할 때마다이 오류가 발생할 수 있습니다. 예를 들면 다음과 같습니다.
public void setChildren(Set<SonEntity> aSet)
{
this.sonEntities = aSet; //This will override the set that Hibernate is tracking.
}
일반적으로 생성자에서 집합을 한 번만 "새"로 만들려고합니다. 목록에 무언가를 추가하거나 삭제할 때마다 새 목록을 할당하는 대신 목록의 내용을 수정해야합니다.
자녀를 추가하려면 :
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);
}
}
그러나이 방법으로 작동하지 않으며 "더 이상 참조되지 않음"오류가 발생하며이 경우 실제로 오해의 소지가 있습니다.
최대 절전 모드가 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);
}
}
}
따라서 첫 번째 호출에서 최대 절전 모드는 특수 클래스를 설치하고 후속 호출에서는 모든 것을 손상시키지 않고 메소드를 직접 사용할 수 있습니다. 클래스를 Bean으로 사용하려면 작동중인 setter가 필요할 수 있으며 적어도 작동하는 것 같습니다.
실제로 내 문제는 엔티티의 equals 및 hashcode에 관한 것입니다. 레거시 코드는 많은 문제를 야기 할 수 있으므로 확인하는 것을 잊지 마십시오. 내가 한 모든 것은 삭제 고아 전략을 유지하고 동등한 항목과 해시 코드를 수정하는 것입니다.
I had the same error. The problem for me was, that after saving the entity the mapped collection was still null and when trying to update the entity the exception was thrown. What helped for me: Saving the entity, then make a refresh (collection is no longer null) and then perform the update. Maybe initializing the collection with new ArrayList() or something might help as well.
HAS RELATION TYPE:
Don't try to instantiate the collection when it's declared in hasMany
, just add and remove objects.
class Parent {
static hasMany = [childs:Child]
}
USE RELATION TYPE:
But the collection could be null only when is declared as a property (use relation) and is not initialized in declaration.
class Parent {
List<Child> childs = []
}
I used @user2709454 approach with small improvement.
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);
}
}
}
}
I had this problem when trying to use TreeSet
. I did initialize oneToMany
with TreeSet
which works
@OneToMany(mappedBy = "question", fetch = FetchType.EAGER, cascade = { CascadeType.ALL }, orphanRemoval=true)
@OrderBy("id")
private Set<WizardAnswer> answers = new TreeSet<WizardAnswer>();
But, this will bring the error described at the question
above. So it seems that hibernate
supported SortedSet
and if one just change the line above to
@OneToMany(mappedBy = "question", fetch = FetchType.EAGER, cascade = { CascadeType.ALL }, orphanRemoval=true)
@OrderBy("id")
private SortedSet<WizardAnswer> answers;
it works like magic :) more info on hibernate SortedSet
can be here
The only time I get this error is when I try to pass NULL into the setter for the collection. To prevent this, my setters look like this:
public void setSubmittedForms(Set<SubmittedFormEntity> submittedForms) {
if(submittedForms == null) {
this.submittedForms.clear();
}
else {
this.submittedForms = submittedForms;
}
}
I am using Spring Boot and had this issue with a collection, in spite of not directly overwriting it, because I am declaring an extra field for the same collection with a custom serializer and deserializer in order to provide a more frontend-friendly representation of the data:
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;
}
It seems that even though I am not overwriting the collection myself, the deserialization does it under the hood, triggering this issue all the same. The solution was to change the setter associated with the deserializer so that it would clear the list and add everything, rather than overwrite it:
@JsonDeserialize(using = AttributeDeserializer.class)
public void setAttributesList(List<Attribute> attributes) {
this.attributes.clear();
this.attributes.addAll(attributes);
}
@OneToMany(mappedBy = 'parent', cascade= CascadeType.ALL, orphanRemoval = true)
List<Child> children = new ArrayList<>()
I experienced the same error when I was adding child object to the existing list of Child Objects.
childService.saveOrUpdate(child);
parent.addToChildren(child);
parentService.saveOrUpdate(parent);
What resolved my problem is: child=childService.saveOrUpdate(child);
Now the child is revive with other details as well and it worked fine.
Adding my dumb answer. We're using Spring Data Rest. This was our pretty standard relationship. The pattern was used elsewhere.
//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
With the relationship we created, it was always intended that the children would be added through their own repo. I had not yet added the repo. The integration test we had was going through a complete lifecycle of the entity via REST calls so the transactions would close between requests. No repo for the child meant the json had the children as part of the main structure instead of in _embedded
. Updates to the parent would then cause problems.
Following solution worked for me
//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;
Instead of assigning new collection
public void setChildren(Set<ChildEntity> children) {
this.children = children;
}
Replace all elements with
public void setChildren(Set<ChildEntity> children) {
Collections.replaceAll(this.children,children);
}
One other cause may be using lombok.
@Builder
- causes to save Collections.emptyList()
even if you say .myCollection(new ArrayList());
@Singular
- ignores the class level defaults and leaves field null
even if the class field was declared as myCollection = new ArrayList()
My 2 cents, just spent 2 hours with the same :)
I was getting A collection with cascade=”all-delete-orphan” was no longer referenced by the owning entity instance
when I was setting parent.setChildren(new ArrayList<>())
. When I changed to parent.getChildren().clear()
, it solved the problem.
Check for more details: HibernateException - A collection with cascade="all-delete-orphan" was no longer referenced by the owning entity instance.
be careful with
BeanUtils.copyProperties(newInsum, insumOld,"code");
This method too break the hibernate.
It might be caused by hibernate-enhance-maven-plugin
. When I enabled enableLazyInitialization
property this exception started on happening on my lazy collection. I'm using hibernate 5.2.17.Final.
Note this two hibernate issues:
Mine was completely different with Spring Boot! For me it was not due to setting collection property.
In my tests I was trying to create an entity and was getting this error for another collection that was unused!
After so much trying I just added a @Transactional
on the test method and it solved it. Don't no the reason though.
I ran into this when updating an entity with a JSON post request. The error occurred when I updated the entity without data about the children, even when there were none. Adding
"children": [],
to the request body solved the problem.
'IT story' 카테고리의 다른 글
stdin, stdout 및 stderr에 대해 혼란 스럽습니까? (0) | 2020.05.14 |
---|---|
MySQL foreign_key_checks가 전체 데이터베이스에 영향을 줍니까? (0) | 2020.05.14 |
IntelliJ 별표 (패키지) 가져 오기를 비활성화 하시겠습니까? (0) | 2020.05.14 |
무효가 아닌 메소드 컴파일에서 누락 된 리턴 문 (0) | 2020.05.14 |
Java 8 스트림 및 어레이 작업 (0) | 2020.05.14 |