हाइबरनेट त्रुटि: समान पहचानकर्ता मान के साथ एक अलग ऑब्जेक्ट पहले से ही सत्र के साथ जुड़ा हुआ था


94

इस कॉन्फ़िगरेशन में मेरे पास अनिवार्य रूप से कुछ ऑब्जेक्ट हैं (वास्तविक डेटा मॉडल थोड़ा अधिक जटिल है):

  • A का बी (B के साथ कई-कई संबंध हैं inverse="true")
  • B का C के साथ एक-से-एक संबंध है (मैंने cascadeनिर्धारित किया है "save-update")
  • C एक प्रकार की श्रेणी / श्रेणी तालिका है।

इसके अलावा, मुझे संभवतः उल्लेख करना चाहिए कि डेटाबेस में सेव के द्वारा प्राथमिक कुंजी उत्पन्न होती है।

अपने डेटा के साथ, मैं कभी-कभी उन समस्याओं में भाग लेता हूं जहां ए में अलग-अलग बी ऑब्जेक्ट का एक सेट होता है, और ये बी ऑब्जेक्ट एक ही सी ऑब्जेक्ट को संदर्भित करते हैं।

जब मैं फोन session.saveOrUpdate(myAObject), मैं कह रहा एक हाइबरनेट त्रुटि मिलती है: "a different object with the same identifier value was already associated with the session: C"। मुझे पता है कि हाइबरनेट एक ही सत्र में एक ही वस्तु को दो बार सम्मिलित / अद्यतन / हटा नहीं सकता है, लेकिन क्या इसके आसपास कोई रास्ता है? ऐसा लगता नहीं है कि यह किसी स्थिति के लिए असामान्य होगा।

इस समस्या के अपने शोध के दौरान, मैंने देखा है कि लोग इसका उपयोग करने का सुझाव देते हैं session.merge(), लेकिन जब मैं ऐसा करता हूं, तो कोई भी "परस्पर विरोधी" वस्तुएं डेटाबेस में सम्मिलित हो जाती हैं, क्योंकि रिक्त मान सभी वस्तुओं के साथ अशक्त हो जाते हैं। स्पष्ट रूप से वह नहीं है जो हम चाहते हैं।

[संपादित करें] एक और बात जिसका मैं उल्लेख करना भूल गया, वह यह है कि (मेरे नियंत्रण से परे वास्तुशिल्प कारणों से), प्रत्येक पढ़ने या लिखने के लिए एक अलग सत्र में किया जाना चाहिए।


देखें कि क्या यह उत्तर आपकी मदद करता है ..
joaonlima

जवाबों:


98

शायद इसकी इसलिए क्योंकि बी ऑब्जेक्ट्स उसी जावा सी ऑब्जेक्ट उदाहरण के लिए संदर्भित नहीं हैं। वे डेटाबेस में एक ही पंक्ति (यानी एक ही प्राथमिक कुंजी) का उल्लेख कर रहे हैं, लेकिन वे इसकी अलग-अलग प्रतियां हैं।

तो क्या हो रहा है कि हाइबरनेट सत्र, जो संस्थाओं का प्रबंधन कर रहा है, जो ट्रैक रखता है कि जावा ऑब्जेक्ट उसी प्राथमिक कुंजी के साथ पंक्ति से मेल खाती है।

एक विकल्प यह सुनिश्चित करना होगा कि ऑब्जेक्ट B की इकाइयाँ जो एक ही पंक्ति को संदर्भित करती हैं, वास्तव में C. के समान ऑब्जेक्ट उदाहरण की बात कर रही हैं। वैकल्पिक रूप से उस सदस्य चर के लिए कैस्केडिंग बंद करें। इस तरह जब B कायम रहता है C नहीं है। आपको C को अलग से मैन्युअल रूप से सहेजना होगा। यदि C एक प्रकार / श्रेणी तालिका है, तो यह संभवतः उस तरह से समझ में आता है।


3
धन्यवाद jbx जैसा कि आपने कहा, यह पता चला है कि बी ऑब्जेक्ट्स मेमोरी में कई सी इंस्टेंस का उल्लेख कर रहे हैं। अनिवार्य रूप से क्या हो रहा है कि मेरे कार्यक्रम का एक हिस्सा सी में पढ़ रहा है, और इसे बी में संलग्न करना है। दूसरा भाग डेटाबेस से एक ही सी के साथ एक अलग बी लोड कर रहा है। दोनों को A से जोड़ा जा रहा है जो सहेजने में त्रुटि को ट्रिगर करता है। मैंने "<pre> none </ pre>" के लिए B-> C संबंध के लिए <प्री> कैस्केड </ प्री> सेट किया है, लेकिन मुझे अभी भी वही त्रुटि मिल रही है। कई-से-एक या एक से कई रिश्तों में, हाइबरनेट को केवल विदेशी कुंजी को बदलने और बाकी के बारे में चिंता न करने का एक तरीका है?
जॉन

1
क्या सी की प्राथमिक कुंजी में कोई आईडी पीढ़ी की रणनीति है? एक अनुक्रम-जनरेटर या कुछ इसी तरह की तरह?
jbx

हां, डेटाबेस में प्रत्येक का अपना अनुक्रम है। जैसा कि आपने उल्लेख किया है, कैस्केडिंग मुद्दा बन गया। हमने टाइप टेबल के लिए कैस्केडिंग बंद कर दिया, और दूसरों के लिए हमने "मर्ज" कैस्केड का उपयोग किया, जिसने हमें उन सभी अशक्त पंक्तियों को बनाने के बिना मर्ज () कॉल करने की अनुमति दी। मैंने आपके उत्तर को अपने अनुसार चिह्नित किया है, धन्यवाद!
जॉन

14
मैंने saveOrUpdate () और BOOM के बजाय मर्ज () का उपयोग किया है! यह काम करता है :)
लाहिरु रुहुनागे

29

बस MERGE को झरना सेट करें, जो कि चाल करना चाहिए।


13

आपको केवल एक काम करने की जरूरत है। भागो session_object.clear()और फिर नई वस्तु को बचाओ। यह सत्र को स्पष्ट करेगा (जैसा कि नाम दिया गया है) और अपने सत्र से आपत्तिजनक डुप्लिकेट ऑब्जेक्ट को हटा दें।


10

मैं @ हेमंत कुमार से सहमत हूं, बहुत-बहुत धन्यवाद। उनके समाधान के अनुसार, मैंने अपनी समस्या हल कर ली।

उदाहरण के लिए:

@Test
public void testSavePerson() {
    try (Session session = sessionFactory.openSession()) {
        Transaction tx = session.beginTransaction();
        Person person1 = new Person();
        Person person2 = new Person();
        person1.setName("222");
        person2.setName("111");
        session.save(person1);
        session.save(person2);
        tx.commit();
    }
}

Person.java

public class Person {
    private int id;
    private String name;

    @Id
    @Column(name = "id")
    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    @Basic
    @Column(name = "name")
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

}

यह कोड हमेशा मेरे आवेदन में गलती करता है: A different object with the same identifier value was already associated with the sessionबाद में, मुझे पता चला कि मैं अपनी प्राथमिक कुंजी को इंगित करना भूल गया था !

मेरा समाधान इस कोड को आपकी प्राथमिक कुंजी पर जोड़ना है:

@GeneratedValue(strategy = GenerationType.AUTO)

6

इसका मतलब है कि आप एक ही वस्तु के संदर्भ में अपनी तालिका में कई पंक्तियों को सहेजने का प्रयास कर रहे हैं।

अपने इकाई वर्ग की आईडी संपत्ति की जाँच करें।

@Id
private Integer id;

सेवा

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(unique = true, nullable = false)
private Integer id;

1
दिए गए विवरण के अनुसार सवाल के साथ मामला नहीं
सुदीप भंडारी

5

उपयोग करके डेटाबेस में हाइबरनेट से ऑब्जेक्ट आईडी असाइन करने के कार्य को स्थानांतरित करें:

<generator class="native"/>

इससे मेरे लिए समस्या हल हो गई।


3

आपके द्वारा डाले जा रहे बीन में एनोटेशन @ जेनरेटेडवैल्यू जोड़ें।


धन्यवाद! यह वास्तव में मेरी समस्या थी
DriLLFreAK100

3

उपरोक्त समस्या को हल करने का एक तरीका ओवरराइड करना होगा hashcode()
बचाने से पहले और बाद में हाइबरनेट सत्र भी फ्लश करें।

getHibernateTemplate().flush();

स्पष्ट रूप से अलग की गई वस्तु को सेट करने से nullभी मदद मिलती है।


2

बस यह संदेश भर आया लेकिन c # कोड में। यकीन नहीं है कि क्या यह प्रासंगिक है (बिल्कुल वही त्रुटि संदेश हालांकि)।

मैं कोड को ब्रेकपॉइंट्स के साथ डिबग कर रहा था और निजी सदस्यों के माध्यम से कुछ संग्रहों का विस्तार किया जबकि डीबगर एक ब्रेकपॉइंट पर था। संरचनाओं के माध्यम से खुदाई किए बिना कोड को फिर से चलाने के बाद त्रुटि संदेश चला गया। ऐसा लगता है कि निजी आलसी-लोड किए गए संग्रह को देखने के कार्य ने NHibernate लोड चीजों को बनाया है जो उस समय लोड नहीं होने चाहिए थे (क्योंकि वे निजी सदस्यों में थे)।

कोड ही एक काफी जटिल लेनदेन में लिपटे हुए हैं जो बड़ी संख्या में रिकॉर्ड और कई निर्भरता को उस लेनदेन (आयात प्रक्रिया) के हिस्से के रूप में अपडेट कर सकते हैं।

उम्मीद है कि इस मुद्दे पर आने वाले किसी और का भी सुराग होगा।


2

हाइबरनेट में "कैसकेड" का पता लगाएं और इसे हटा दें। जब आप "कैस्केड" उपलब्ध करते हैं, तो यह अन्य संचालन पर अन्य संचालन (सेव, अपडेट और डिलीट) को कॉल करेगा, जिसका संबंधित वर्गों के साथ संबंध है। तो समान पहचान मूल्य होगा। इसने मेरे साथ काम किया।


1

मुझे कुछ दिनों के लिए यह त्रुटि हुई थी और मैंने इस त्रुटि को ठीक करने में बहुत समय बिताया।

 public boolean save(OrderHeader header) {
    Session session = sessionFactory.openSession();


    Transaction transaction = session.beginTransaction();

    try {
        session.save(header);

        for (OrderDetail detail : header.getDetails()) {
            session.save(detail);
        }

        transaction.commit();
        session.close();

        return true;
    } catch (HibernateException exception) {

        exception.printStackTrace();
        transaction.rollback();
        return false;
    }
}

इससे पहले कि मैं यह त्रुटि प्राप्त करूं, मैंने ऑर्डरडेटिल ऑब्जेक्ट पर आईडी पीढ़ी प्रकार का उल्लेख नहीं किया है। जब ऑर्डरडेल का आईडी जनरेट किए बिना यह प्रत्येक ऑर्डरडाईटेल ऑब्जेक्ट के लिए 0 आईडी रखता है। यह क्या #jbx समझाया। हाँ यह सबसे अच्छा जवाब है। यह एक उदाहरण है कि यह कैसे होता है।


1

अपनी क्वेरी का कोड पहले रखने का प्रयास करें। वह मेरी समस्या को ठीक करे। जैसे इसे बदलें:

query1 
query2 - get the error 
update

इसके लिए:

query2
query1
update

0

आप अद्यतन क्वेरी को कॉल करने से पहले ऑब्जेक्ट के पहचानकर्ता को सेट नहीं कर सकते हैं।


3
अगर वह नहीं होता तो उसे यह समस्या नहीं होती। समस्या यह है कि उसके पास एक ही पहचानकर्ता के साथ दो वस्तुएं हैं।
अकलू

0

जब मैं इस तरह से एक पंक्ति सम्मिलित करता हूं, तो प्राथमिक कुंजी पीढ़ी गलत होने के कारण मैं समस्या से मिला:

public void addTerminal(String typeOfDevice,Map<Byte,Integer> map) {
        // TODO Auto-generated method stub
        try {
            Set<Byte> keySet = map.keySet();
            for (Byte byte1 : keySet) {
                Device device=new Device();
                device.setNumDevice(DeviceCount.map.get(byte1));
                device.setTimestamp(System.currentTimeMillis());
                device.setTypeDevice(byte1);
                this.getHibernateTemplate().save(device);
            }
            System.out.println("hah");
        }catch (Exception e) {
            // TODO: handle exception
            logger.warn("wrong");
            logger.warn(e.getStackTrace()+e.getMessage());
        }
}

मैं पहचान के लिए आईडी जनरेटर वर्ग को बदलता हूं

<id name="id" type="int">
    <column name="id" />
    <generator class="identity"  />
 </id>

0

मेरे मामले में केवल फ्लश () काम नहीं किया। मुझे फ्लश () के बाद एक स्पष्ट () का उपयोग करना था।

public Object merge(final Object detachedInstance)
    {
        this.getHibernateTemplate().flush();
        this.getHibernateTemplate().clear();
        try
        {
            this.getHibernateTemplate().evict(detachedInstance);
        }
}


0

अगर मेरी आईडीई में एक भाव टैब खुला है जो हाइबरनेट बना रहा था तो इस अपवाद को उत्पन्न करने वाली वस्तु पर कॉल मिलता है। मैं इसी ऑब्जेक्ट को हटाने की कोशिश कर रहा था। इसके अलावा, मेरे पास डिलीट कॉल पर एक ब्रेकपॉइंट है जो इस त्रुटि को प्राप्त करने के लिए आवश्यक प्रतीत होता है। बस एक और एक्सप्रेशन टैब को फ्रंट टैब बनाने या सेटिंग में बदलाव करने के लिए ताकि आइडिया ब्रेकपॉइंट्स पर न रुके, इस समस्या को हल किया।


0

सुनिश्चित करें, आपकी इकाई में सभी मैप की गई इकाइयों के साथ एक ही पीढ़ी प्रकार है

Ex: UserRole

public class UserRole extends AbstractDomain {

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;

private String longName;

private String shortName;

@Enumerated(EnumType.STRING)
private CommonStatus status;

private String roleCode;

private Long level;

@Column(columnDefinition = "integer default 0")
private Integer subRoleCount;

private String modification;

@ManyToOne(fetch = FetchType.LAZY)
private TypeOfUsers licenseType;

}

मापांक :

public class Modules implements Serializable {

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;

private String longName;

private String shortName;

}

मैपिंग के साथ मुख्य इकाई

public class RoleModules implements Serializable{

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;

@ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.MERGE)
private UserRole role;

@ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.MERGE)
private Modules modules;

@Type(type = "yes_no")
private boolean isPrimaryModule;

public boolean getIsPrimaryModule() {
    return isPrimaryModule;
}

}


0

पिछले सभी उत्तरों के अलावा, बड़े पैमाने पर प्रोजेक्ट में इस समस्या का एक संभावित समाधान, यदि आपकी अपनी कक्षाओं के लिए एक वैल्यू ऑब्जेक्ट का उपयोग करते हुए, आप VO ट्रांस्फ़ॉर्मर वर्ग में आईडी विशेषता सेट नहीं करते हैं।


0

बस वर्तमान लेनदेन करें।

currentSession.getTransaction().commit();

अब आप एक और लेनदेन शुरू कर सकते हैं और इकाई पर कुछ भी कर सकते हैं


0

एक और मामला जब एक ही त्रुटि संदेश उत्पन्न हो सकता है, तो कस्टम allocationSize:

@Id
@Column(name = "idpar")
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "paramsSequence")
@SequenceGenerator(name = "paramsSequence", sequenceName = "par_idpar_seq", allocationSize = 20)
private Long id;

बिना मिलान के

alter sequence par_idpar_seq increment 20;

डालने के दौरान बाधा सत्यापन का कारण बन सकता है (कि एक को समझना आसान है) या "एक ही पहचानकर्ता मूल्य के साथ एक अलग वस्तु पहले से ही सत्र के साथ जुड़ा हुआ था" - यह मामला कम स्पष्ट था।

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