2012-03-12 12 views
9

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

यह मेरा मॉडल है:

public class MessageNew 
    { 
     public virtual int Id { get; set; } 
     public virtual string Content { get; set; } 
     public virtual string Subject { get; set; } 
     public virtual User User { get; set; } 
     public virtual bool IsSent { get; set; } 
     public virtual string AmazonMessageId { get; set; } 
    } 

और मेरे मानचित्रण

public class MessageNewMap : ClassMap<MessageNew> 
{ 
    public MessageNewMap() 
    { 
     Id(x => x.Id); 
     Map(x => x.Content).CustomSqlType("text"); 
     Map(x => x.Subject); 
     Map(x => x.AmazonMessageId); 
     Map(x => x.IsSent); 

     References(x => x.User); 
    } 
} 
यहाँ

जहां अपवाद तब होता है:

foreach (var userToSend in usersToSend) 
{ 
    string body = MailHelper.BuildSomeBody() 
    if (userToSend != CurrentUser) 
    { 
     MessageNew message = new MessageNew 
     { 
      User = userToSend, 
      IsSent = false, 
      Content = body, 
      Subject = subject 
     }; 
     session.Save(message); // Exception thrown 
    } 
} 

अपवाद विवरण:

NHibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session: 1779, of entity: Models.MessageNew 
    at NHibernate.Engine.StatefulPersistenceContext.CheckUniqueness(EntityKey key, Object obj) 
    at NHibernate.Event.Default.AbstractSaveEventListener.PerformSaveOrReplicate(Object entity, EntityKey key, IEntityPersister persister, Boolean useIdentityColumn, Object anything, IEventSource source, Boolean requiresImmediateIdAccess) 
    at NHibernate.Event.Default.AbstractSaveEventListener.SaveWithGeneratedId(Object entity, String entityName, Object anything, IEventSource source, Boolean requiresImmediateIdAccess) 
    at NHibernate.Event.Default.DefaultSaveOrUpdateEventListener.SaveWithGeneratedOrRequestedId(SaveOrUpdateEvent event) 
    at NHibernate.Event.Default.DefaultSaveOrUpdateEventListener.EntityIsTransient(SaveOrUpdateEvent event) 
    at NHibernate.Event.Default.DefaultSaveOrUpdateEventListener.OnSaveOrUpdate(SaveOrUpdateEvent event) 
    at NHibernate.Impl.SessionImpl.FireSave(SaveOrUpdateEvent event) 
    at NHibernate.Impl.SessionImpl.Save(Object obj) 

आईडी जनरेटर डेटाबेस संचालित ऑटो-वृद्धि आईडी जनरेटर है। (हिलो या कोई अन्य नहीं)। NHibernate संस्करण 3.2.0 है।

मैंने इक्वाल्स और गेटहाशकोड को अधिभारित करने की कोशिश की है, कोई भाग्य नहीं।

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

मैं अपने पूरे प्रोजेक्ट पर एक ही संरचना का उपयोग कर रहा हूं, और यह हर जगह अच्छी तरह से काम करता है लेकिन यह। मुझे संदेह है कि यह "सामग्री" संपत्ति के कारण हो सकता है, जो पाठ है और एक बड़ी स्ट्रिंग पर सेट है।

मुझे यहां क्या याद आ रही है? या NHibernate कुछ याद आ रही है?

+1

आपके मानचित्रण में आपके पास 'क्लास मैप ' है लेकिन वर्ग 'संदेश' दिखा रहा है यह एक टाइपो है? – Rippo

+0

हां, वास्तव में यह "संदेश नया" है। चेतावनी के लिए धन्यवाद, मैंने पोस्ट संपादित किया। – SadullahCeran

+0

क्या आपने कभी यह पता लगाया है? – BueKoW

उत्तर

1

messagenew बराबर लागू करने और GetHashCode

public class MessageNew 
{ 
    public virtual int Id { get; set; } 

    public override bool Equals(object obj) 
    { 
     var other = obj as MessageNew; 
     return (other != null) && (IsTransient ? ReferenceEquals(this, other) : Id == other.Id; 
    } 

    private int? _cachedHashcode; // because Hashcode should not change 
    public override int GetHashCode() 
    { 
     if (_cachedHashcode == null) 
      _cachedHashcode = IsTransient ? base.GetHashCode() : Id.GetHashCode(); 

     return _cachedHashcode.Value; 
    } 

    public bool IsTransient { get { return Id == 0; } } 
} 
+1

टिप के लिए धन्यवाद। मैंने ओवरराइड किया, लेकिन कोई भाग्य नहीं :( – SadullahCeran

0

कि अपवाद चाहिए आम तौर पर दर्शाता आप एक ही पहचानकर्ता मूल्य है जो आप एक ही सत्र से अधिक का प्रबंधन करने की कोशिश कर रहे साथ एक वस्तु की 2 अलग उदाहरणों है।

0

आपके पास पहले से ही उस आईडी के साथ इकाई का एक और उदाहरण है।

दो संभावित समस्याओं:

1 - संस्था की अपनी तुलना काम नहीं करता। आप रद्द कर सकते थे सुझाव दिया बराबर के रूप में या आप अपने परीक्षण का मामला है कि आप से पहले का उपयोग बदल सकता है सहेजें:

if (userToSend.Id != CurrentUser.Id) 

2 - आप अपनी इकाई के लिए एक अद्वितीय ID नहीं दे रही हैं, आप या तो एक आईडी स्वयं असाइन करना, NHHernate एक उत्पन्न करता है या आपके एसक्यूएल सर्वर आपके लिए यह करते हैं। आपके मैपिंग में यह बताया गया है कि पहचान का उपयोग किया जाना चाहिए (फ्लुएंट डिफ़ॉल्ट) लेकिन क्या आपने अपने डेटाबेस में कॉलम सेट और पहचान कॉलम सेट अप किया है?

+0

उत्तर के लिए धन्यवाद। अपवाद उस पंक्ति (उपयोगकर्ताओं की तुलना) पर नहीं हुआ है। यदि (userToSend! = CurrentUser) केवल व्यवसाय तर्क है। अपवाद फेंक दिया जाता है जहां संदेश सत्र में सहेजा जाता है दूसरे के लिए: कॉलम पहचान कॉलम है और मैं डेटाबेस जेनरेट आईडी चाहता हूं, इसलिए मैंने आईडी जनरेटर नहीं लगाया। इसके अलावा, आईडी को अच्छी तरह से बनाया गया है, – SadullahCeran

1

मैंने कुछ एनएच कोड पढ़ा। यह मूल रूप से डेटाबेस में नए आईडी को अपनी आईडी प्राप्त करने के लिए सम्मिलित करता है। फिर यह जांचता है कि डेटाबेस द्वारा उत्पन्न आईडी वास्तव में अद्वितीय है या नहीं। यदि नहीं, तो आपको यह अपवाद मिलता है।

आपका डेटाबेस अद्वितीय आईडी उत्पन्न नहीं कर रहा है। आप शायद इसे एक पहचान कॉलम पर सेट करना भूल गए हैं।

या पहचान पर 0 के बजाय 1.

+0

कोई समस्या नहीं है जो सबसे अधिक संभावना है – bernhardrusch

+0

कॉलम एक पहचान कॉलम है, जहां कॉलम एक पहचान कॉलम है ऑटो-वृद्धि को सही पर सेट किया गया है। टिप के लिए धन्यवाद, लेकिन यह मेरा मामला नहीं है – SadullahCeran

+0

और पहचान बीज 1 है, 0 नहीं? –

0

मेरे ले गिनती शुरू होता है: यदि आप एक आईडी जनरेटर की घोषणा नहीं कर रहे हैं। इसलिए, जैसे ही आपको सत्र में दो संदेश नए उदाहरण मिलते हैं, वे दोनों आईडी के रूप में 0 होंगे।

+0

हालांकि, डिफ़ॉल्ट कॉन्फ़िगरेशन पहचान आईडी जनरेटर है, और मैं इसे पूरे प्रोजेक्ट में उपयोग कर रहा हूं, न केवल इस मॉडल के लिए।और यह ठीक से काम किया। – SadullahCeran

1

आप सत्र से ऑब्जेक्ट निष्कासित करने के लिए Evict() का उपयोग कर सकते हैं और फिर आप जो भी चाहें कर सकते हैं। यह त्रुटि तब होती है जब आपके पास किसी अन्य सत्र में एक ही ऑब्जेक्ट होता है।

+3

स्टैक ओवरव्लो में आपका स्वागत है। याद रखें कि छोटे/सरल उत्तरों को हमेशा उन दस्तावेज़ों से लिंक करके मजबूर किया जा सकता है जो उनकी समानता का समर्थन करते हैं। –

0

शायद थोड़ी देर हो चुकी है लेकिन उम्मीद है कि इससे मदद मिलती है।

मुझे एक ही समस्या थी जब मैं उसी सत्र में एक ऑब्जेक्ट के कई उदाहरणों को सहेजने की कोशिश कर रहा था, जिसमें ऑटो जनरेटेड कॉलम था। मेरा समाधान एक अलग मूल्य दे रहा था और प्रत्येक इकाई के लिए इसे मैन्युअल रूप से असाइन करता था, इसलिए निबर्ननेट इसे उस इकाई के लिए प्राथमिक प्राथमिक कुंजी के रूप में नहीं पहचानता है।

4

कभी-कभी यह खुशी होती है जब हम ऑब्जेक्ट को एक ही नई वस्तु पर असाइन करते हैं। तो सबसे पहले अपने मॉडल और व्यूमोडेल की जांच करें कि वे समान नहीं हैं।

-1
 [..] 
    }; 
    session.Clear(); 
    session.Save(message); 

इसे आजमाएं, मेरी मदद की।

+3

आप थोड़ा और विस्तार से जाना चाहेंगे। कोड की केवल दो पंक्तियां और "इसे आजमाएं" वास्तव में एक उत्तर नहीं है। – Fred

3

मुझे भी इसी तरह की समस्या थी। मैं विचार विमर्श, ट्यूटोरियल और मंचों का एक बहुत माध्यम से चला गया, लेकिन कुछ इकाई परीक्षण लेखन के बाद, मुझे एहसास हुआ:

1) session.Contains विधि उदाहरणों

के साथ काम करता

2) session.Save/SaveorUpdate आईडी

साथ काम करता है

यह त्रुटि आपको सत्र में एक ही आईडी के साथ ऑब्जेक्ट का एक और उदाहरण दिखाती है। इसलिए, इसमें वापसी झूठी है क्योंकि आप अलग-अलग उदाहरणों पर काम कर रहे हैं और सेव/सेवॉर अपडेट एक अपवाद फेंकता है क्योंकि सत्र में एक ही आईडी वाला कोई अन्य ऑब्जेक्ट है। मैं (मेरी समस्या नौकरी इकाई में था) इस तरह मेरी समस्या हल कर लिए हैं:

Job lJob = lSession.Load<Job>(this.ID); 

if(lJob.ID==this.ID) 
    lSession.Evict(lJob); 

lSession.SaveOrUpdate(this); 

मुझे आशा है कि यह मदद करता है आप

-1

से पहले Session.Save या Session.SaveOrUpdate

Session.Clear(); 
Session.Flush(); 

यह दो पंक्तियों के नीचे जोड़ें सत्र के साथ सभी कैश किए गए इकाइयों को साफ़ कर देगा।