[java] 최대 절전 모드-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에 관한 것입니다. 레거시 코드는 많은 문제를 일으킬 수 있으므로 반드시 확인하십시오. 내가 한 모든 것은 삭제 고아 전략을 유지하고 동등한 항목과 해시 코드를 수정하는 것입니다.
답변
나는 같은 오류가 있었다. 나에게 문제는 엔터티를 저장 한 후 매핑 된 컬렉션이 여전히 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);
}
}
}
}