हाइबरनेट - कैस्केड के साथ एक संग्रह = "ऑल-डिलीट-ऑर्फ़न" को अब मालिकाना उदाहरण के उदाहरण द्वारा संदर्भित नहीं किया गया था


225

जब मेरी इकाई को अपडेट करने का प्रयास किया जा रहा है, तो मुझे निम्नलिखित समस्या हो रही है:

"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;
}

मैंने सेट <..> को साफ करने की कोशिश की है, केवल इस के अनुसार: समस्या को "संभव" कैसे हल करें लेकिन यह काम नहीं किया।

यदि आपके पास कोई विचार है, तो कृपया मुझे बताएं।

धन्यवाद!


1
@ mel3kings, आपके द्वारा प्रदान किया गया लिंक अब सक्रिय नहीं है।
ओपल


तत्वों को हटाते समय परस्पर संग्रह का उपयोग करने का प्रयास करें। उदाहरण के लिए उपयोग नहीं है something.manyother.remove(other)अगर manyotherएक है List<T>। बहुत से ArrayList<T>orphanDelete = true
म्यूटेबल

जवाबों:


220

उन सभी स्थानों की जाँच करें, जहाँ आप पुत्र-संबंधी कुछ बता रहे हैं। जिस लिंक को आपने संदर्भित किया है वह एक नया 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);
}

8
दरअसल, मेरी समस्या मेरी संस्थाओं के बराबरी और हैशकोड के बारे में थी। एक विरासत कोड बहुत सारी समस्याएं ला सकता है, इसे जांचना कभी न भूलें। मैंने बस इतना किया है कि डिलीट-अनाथ रणनीति और सही बराबर और हैशकोड रखें।
22 फरवरी को axcdnt

6
मुझे खुशी है कि आपने अपनी समस्या हल कर ली। बराबरी और हैशकोड ने मुझे कई बार हाइबरनेट के साथ काट दिया है। "[हल]" के साथ प्रश्न का शीर्षक अपडेट करने के बजाय, आपको आगे बढ़ना चाहिए और अपना उत्तर पोस्ट करना चाहिए और फिर इसे स्वीकृत उत्तर के रूप में चिह्नित करना चाहिए।
दिमागीमास

धन्यवाद, मैं कुछ इसी तरह से भागा और उस सेट को खाली करने के लिए अपने सेटर को बाहर कर दिया ..
सिद्धार्थ

हाँ, खाली सूचियों पर भी आपको यह त्रुटि मिलती है। मुझे उम्मीद नहीं है कि क्योंकि कोई अनाथ नहीं हैं (सूची खाली थी)।
बीबी

4
आमतौर पर आप एक निर्माता में एक बार केवल "नया" सेट करना चाहते हैं। जब भी आप सूची में कुछ जोड़ना या हटाना चाहते हैं तो आपको नई सूची असाइन करने के बजाय सूची की सामग्री को संशोधित करना होगा। सबसे छोटा
निखिल साहू

109

प्रक्रिया:

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);
    }
}

1
@Skuld मुझे एक समान समस्या है और मैंने आपके समाधान को लागू किया (सेटर विधि में मैंने बच्चों के संग्रह को साफ़ कर दिया - this.children.clear) () - और मैंने नए बच्चों को जोड़ा - this.children.addAll (बच्चे)। इस परिवर्तन से मेरी समस्या ठीक नहीं हुई। मुझे अभी भी "एक संग्रह कैस्केड के साथ है =" ऑल-डिलीट-ऑर्फ़न "का स्वामित्व इकाई उदाहरण द्वारा संदर्भित नहीं था" अपवाद। क्या आपके पास एक विचार है क्यों? आपका बहुत बहुत धन्यवाद!
ओवड्रसन

@ovdsrn क्षमा करें, यह मेरा उत्तर नहीं है, मैंने अभी उत्तर के प्रारूपण को हल किया है, मूल लेखक (kmmanu) आपकी मदद करने में सक्षम हो सकता है (या यदि आप अपना परिदृश्य अलग करना चाहते हैं तो एक नया प्रश्न शुरू कर सकते हैं। मूल प्रश्न यहाँ पूछा गया) सौभाग्य
स्कुलड

1
यह अच्छी तरह से काम करता है, लेकिन इतना अच्छा नहीं है जब बच्चों को एक नेस्टेड हाइबरनेट घटक में समाहित किया जाता है और घटक को एंटिटी में शून्य बना दिया जाता है। फिर आपको वही त्रुटि मिलती है। ऐसा इसलिए है क्योंकि बच्चों का स्वामी रूट एंटिटी है न कि वह घटक जो अशक्त बना हुआ है ... एक ऐसा, एक घटक को कभी भी अशक्त नहीं होने दिया जाता है, बल्कि इसके परिणामस्वरूप एक नष्ट () विधि के लिए आगे होना चाहिए। बच्चा ... कम से कम, मुझे एक बेहतर समाधान नहीं पता है ... यह एक तरह का संग्रह स्पष्ट है () निर्माण लेकिन फिर नष्ट होने () के माध्यम से एक घटक पर ...
edbras

उपरोक्त जानकारी के लिए इस पोस्ट को भी देखें: stackoverflow.com/questions/4770262/…
edbras

7
son.ntities.clear () पर इस .sonEntities.retainAll (aSet) का उपयोग करें क्योंकि यदि aSet == this.sonEntities (यानी एक ही ऑब्जेक्ट) आप इससे पहले कि आप इसे जोड़ने के लिए सेट को साफ़ कर देंगे!
मार्टिन

33

जब मैंने विभिन्न स्थानों पर पढ़ा कि हाइबरनेट आपको संग्रह करने के लिए असाइन करना पसंद नहीं था, तो मैंने माना कि सबसे सुरक्षित बात यह है कि स्पष्ट रूप से इसे इस तरह अंतिम बनाना होगा:

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

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

हालाँकि, यह काम नहीं करता है, और आपको "अब संदर्भित नहीं" त्रुटि से डर लगता है, जो वास्तव में इस मामले में काफी भ्रामक है।

यह पता चलता है कि हाइबरनेट आपके सेटरॉल्स विधि को कॉल करता है और यह चाहता है कि इसकी विशेष संग्रह कक्षा यहां स्थापित हो, और आपके संग्रह वर्ग को स्वीकार नहीं करेगा। यह मुझे एक लंबी अवधि के लिए स्टम्प्ड किया गया था, आपके सेट विधि में आपके संग्रह को असाइन नहीं करने के बारे में सभी चेतावनियों को पढ़ने के बावजूद।

इसलिए मैंने इसे बदल दिया:

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);
  }
}
}

ताकि पहली कॉल पर, हाइबरनेट अपनी विशेष कक्षा स्थापित करे, और बाद की कॉल पर आप सब कुछ बर्बाद किए बिना विधि का उपयोग कर सकते हैं। यदि आप अपनी कक्षा को बीन के रूप में उपयोग करना चाहते हैं, तो आपको संभवतः एक कामकाजी सेटर की आवश्यकता है, और यह कम से कम काम करने लगता है।


2
आप रिटेल को क्यों बुला रहे हैं ()? AddAll () द्वारा स्पष्ट () क्यों नहीं किया गया?
edbras

1
"आप रिटेन क्यों कह रहे हैं ()? क्यों नहीं स्पष्ट () के बाद AddAll ()?" अच्छा सवाल है, मुझे लगता है कि मैं इस धारणा के तहत काम कर रहा था कि हाइबरनेट को डेटाबेस अपडेट के रूप में देखने की संभावना कम होगी यदि आप आइटम को फिर से जोड़ने से पहले नहीं हटाते हैं। लेकिन मुझे संदेह है कि यह वैसे भी काम नहीं करता है।
xpusostomos

2
यदि आपको समान सेट ऑब्जेक्ट में पास होना है तो आपको रिटेल () का उपयोग स्पष्ट () से अधिक करना चाहिए अन्यथा आप भूमिकाओं को मिटा सकते हैं। उदाहरण के लिए: user.setRoles (user.getRoles ()) == user.roles.clear ()
मार्टिन

2
जब आप orphanRemoval = true सेट करते हैं और आप एक रिकॉर्ड बनाते हैं जहां यह संग्रह शून्य है, तो आपको यह त्रुटि भी मिलती है। तो: orphanremoval = true के साथ oneToMany b है। जब आप A को B = null बनाते हैं, तो यह समस्या ट्रिगर हो जाती है। आरंभ करने और इसे अंतिम बनाने के लिए आपका समाधान सबसे अच्छा लगता है।
लॉरेंस

धन्यवाद! मैं अपनी सूची को प्रारंभ कर रहा था List<String> list = new ArrayList<>();List<String> list = null;समस्या को ठीक करने के लिए इसे बदलना :)
कट्टरपंथी

19

दरअसल, मेरी समस्या मेरी संस्थाओं के बराबरी और हैशकोड के बारे में थी। एक विरासत कोड बहुत सारी समस्याएं ला सकता है, इसे जांचना कभी न भूलें। मैंने बस इतना किया है कि डिलीट-अनाथ रणनीति और सही बराबर और हैशकोड रखें।


9
कृपया, एक अच्छी तरह से बनाए गए समान और हैशकोड विधियों का एक उदाहरण? क्योंकि मेरे पास बहुत सारी समस्याएं हैं: या मैं अपने सेट को अपडेट नहीं कर सकता या मुझे एक StackOverflow त्रुटि मिलती है। मैंने यहां एक प्रश्न खोला: stackoverflow.com/questions/24737145/… । धन्यवाद
SaganTheBest

11

मेरी भी यही त्रुटि थी। मेरे लिए समस्या यह थी, कि इकाई को बचाने के बाद मैप किया गया संग्रह अभी भी अशक्त था और जब इकाई को अद्यतन करने की कोशिश की जा रही थी तो अपवाद को फेंक दिया गया था। मेरे लिए क्या मदद की: इकाई को सहेजना, फिर एक ताज़ा करें (संग्रह अब शून्य नहीं है) और फिर अद्यतन करें। हो सकता है कि नए ArrayList () या कुछ के साथ संग्रह को आरम्भ करने में भी मदद मिले।


अशक्त के बजाय नए ArrayList भेजना, मेरे लिए काम किया। धन्यवाद
rpajaziti

4

संबंध संबंध प्रकार:


जब यह घोषित किया जाता है hasMany, तो केवल वस्तुओं को जोड़ने और हटाने के लिए संग्रह को तुरंत करने की कोशिश न करें ।

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

उपयोग संबंध प्रकार:


लेकिन संग्रह केवल तभी शून्य हो सकता है जब एक संपत्ति के रूप में घोषित किया जाता है (संबंध का उपयोग करें) और घोषणा में प्रारंभिक नहीं है।

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

4

मैंने छोटे सुधार के साथ @ 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

उपयोग करने की कोशिश करते समय मुझे यह समस्या थी 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हो सकती है


शायद, यह उपयोगकर्ता के लिए बेहतर है Collections.emptySet () एक सिंगलटन खाली सूची का उपयोग करने के लिए
ryzhman

3

केवल एक बार मुझे यह त्रुटि मिलती है जब मैं संग्रह के लिए NULL को सेटर में पास करने का प्रयास करता हूं। इसे रोकने के लिए, मेरे निवासी इस तरह दिखते हैं:

public void setSubmittedForms(Set<SubmittedFormEntity> submittedForms) {
    if(submittedForms == null) {
        this.submittedForms.clear();
    }
    else {
        this.submittedForms = submittedForms;
    }
}

3

JSON पोस्ट अनुरोध के साथ एक इकाई को अपडेट करते समय मैं इसमें भाग गया। त्रुटि तब हुई जब मैंने बच्चों के बारे में डेटा के बिना इकाई को अपडेट किया, तब भी जब कोई नहीं था। जोड़ा जा रहा है

"children": [],

अनुरोध निकाय ने समस्या को हल किया।


1

एक अन्य कारण लोबोक का उपयोग हो सकता है।

@Builder- Collections.emptyList()कहने पर भी बचाने का कारण बनता है.myCollection(new ArrayList());

@Singular- क्लास लेवल डिफॉल्ट्स को नजरअंदाज कर देता है और nullक्लास फील्ड को डिक्लेयर कर दिया जाता हैmyCollection = new ArrayList()

मेरे 2 सेंट, बस उसी के साथ 2 घंटे बिताए :)


1

A collection with cascade=”all-delete-orphan” was no longer referenced by the owning entity instanceजब मैं सेटिंग कर रहा था तो मुझे मिल रहा था parent.setChildren(new ArrayList<>())। जब मैंने parent.getChildren().clear()इसे बदल दिया , तो यह समस्या हल हो गई।

अधिक जानकारी के लिए जाँच करें: हाइबरनेट अपवाद - कैस्केड के साथ एक संग्रह = "ऑल-डिलीट-ऑर्फ़न" का स्वामित्व इकाई उदाहरण द्वारा संदर्भित नहीं किया गया था


1

मैं स्प्रिंग बूट का उपयोग कर रहा हूं और इस मुद्दे को एक संग्रह के साथ रखा गया था, इसके बावजूद इसे सीधे अधिलेखित नहीं किया गया है, क्योंकि मैं एक अधिक धारावाहिक के साथ एक ही संग्रह के लिए एक अतिरिक्त क्षेत्र की घोषणा कर रहा हूं और अधिक सीमांत-अनुकूल प्रतिनिधित्व प्रदान करने के लिए 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;
  }

ऐसा लगता है कि भले ही मैं खुद संग्रह को अधिलेखित नहीं कर रहा हूं , लेकिन इस चित्रण को हूड के तहत करता है। समाधान deserializer के साथ जुड़े सेटर को बदलने के लिए था ताकि यह सूची को साफ कर सके और सब कुछ जोड़ सके, इसके बजाय इसे ओवरराइट करें:

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

1

मेरे पास एक ही मुद्दा था, लेकिन यह तब था जब सेट शून्य था। केवल सूची में सेट संग्रह में काम पाते हैं। आप JPA एनोटेशन भ्रूण = FetchType.EAGER के इंस्टेंस्ड हाइबरनेट एनोटेशन @LazyCollection (LazyCollectionOption.FALSE) की कोशिश कर सकते हैं।

मेरा समाधान: यह मेरा कॉन्फ़िगरेशन और काम ठीक है

@OneToMany(mappedBy = "format", cascade = CascadeType.ALL, orphanRemoval = true)
@LazyCollection(LazyCollectionOption.FALSE)
private Set<Barcode> barcodes;

@OneToMany(mappedBy = "format", cascade = CascadeType.ALL, orphanRemoval = true)
@LazyCollection(LazyCollectionOption.FALSE)
private List<FormatAdditional> additionals;

1
@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);

अब बच्चा अन्य विवरणों के साथ पुनर्जीवित होता है और यह ठीक काम करता है।


0

मेरे गूंगे जवाब को जोड़ते हुए। हम स्प्रिंग डेटा रेस्ट का उपयोग कर रहे हैं। यह हमारा सुंदर मानक संबंध था। पैटर्न कहीं और इस्तेमाल किया गया था।

//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 कॉल के माध्यम से इकाई के एक पूरे जीवन चक्र के माध्यम से जा रहे थे ताकि लेनदेन अनुरोधों के बीच बंद हो जाए। बच्चे के लिए कोई रेपो का मतलब यह नहीं था कि बच्चे के बजाय मुख्य संरचना के हिस्से के रूप में बच्चे थे _embedded। माता-पिता के लिए अद्यतन तब समस्याएँ पैदा करेगा।


0

निम्नलिखित समाधान ने मेरे लिए काम किया

//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

नए कलेक्शन को असाइन करने के बजाय

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

सभी तत्वों को बदलें

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


0

इसके कारण हो सकता है hibernate-enhance-maven-plugin। जब मैंने enableLazyInitializationसंपत्ति को सक्षम किया तो यह अपवाद मेरे आलसी संग्रह पर होने लगा। मैं हाइबरनेट 5.2.17 का उपयोग कर रहा हूं। फ़ाइनल।

इस दो हाइबरनेट मुद्दों पर ध्यान दें:


0

मेरा स्प्रिंग स्प्रिंग के साथ बिल्कुल अलग था! मेरे लिए यह संग्रह संपत्ति स्थापित करने के कारण नहीं था।

अपने परीक्षणों में मैं एक इकाई बनाने की कोशिश कर रहा था और एक और संग्रह के लिए यह त्रुटि हो रही थी जो अप्रयुक्त थी!

इतनी कोशिश के बाद मैंने सिर्फ @Transactionalटेस्ट पद्धति पर जोड़ा और इसे हल किया। हालांकि कोई कारण नहीं है।


0

यह पिछले उत्तरों के विपरीत है, मेरे पास बिल्कुल वही त्रुटि थी: "कैस्केड के साथ एक संग्रह =" ऑल-डिलीट-अनाथ "अब संदर्भित नहीं था ...." जब मेरा सेटर फ़ंक्शन इस तरह दिखता था:

public void setTaxCalculationRules(Set<TaxCalculationRule> taxCalculationRules_) {
    if( this.taxCalculationRules == null ) {
        this.taxCalculationRules = taxCalculationRules_;
    } else {
        this.taxCalculationRules.retainAll(taxCalculationRules_);
        this.taxCalculationRules.addAll(taxCalculationRules_);
    }
}

और फिर यह गायब हो गया जब मैंने इसे सरल संस्करण में बदल दिया:

public void setTaxCalculationRules(Set<TaxCalculationRule> taxCalculationRules_) {
    this.taxCalculationRules = taxCalculationRules_;
}

(हाइबरनेट संस्करण - 5.4.10 और 4.3.11 दोनों की कोशिश की। सेटर में सरल असाइनमेंट पर वापस आने से पहले कई तरह के समाधानों की कोशिश कर रहे हैं। अब ऐसा क्यों किया गया है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.