2012-06-29 10 views
9

ऐसे कई सवाल और जवाब और लेख इस सवाल का उपलब्ध हैं, लेकिन मेरी राय में कोई वास्तविक स्पष्ट/सही जवाबहम वास्तव में कैसे implenting किया जाना चाहिए बराबर है और GetHashCode NHibernate संस्थाओं के लिए

मेरे लिए Ayende है प्रतीत हो रहा है सबसे अच्छा सामान्य कार्यान्वयन अब तक कि मैंने देखा है: http://ayende.com/blog/2500/generic-entity-equality

.... लेकिन इसे 2007 ....

से है इस 'सबसे अच्छा तरीका है' विशेष रूप से करने के संबंध में इन तरीकों को लागू करने के है NHibernate 3.2 जिसमें प्रॉक्सी implemen में कुछ अंतर शामिल हैं पिछले संस्करणों के लिए tation?

+0

कृपया सही जवाब के रूप में हाँ जवाब निशान । –

उत्तर

2

मेरी व्यक्तिगत सिफारिश इन तरीकों को लागू नहीं करना है, क्योंकि ऐसा करने से कई मामलों में लोड हो रहा है जहां यह वास्तव में आवश्यक नहीं है।

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

+0

जब आपके पास प्रॉक्सी और गैर-प्रॉक्सी का आलसी लोड संग्रह होता है तो क्या होगा? उस संग्रह के खिलाफ तुलना ** ** विफल हो जाएगी **। – TheCloudlessSky

+0

@thecloudlesssky बस आईडी द्वारा मैन्युअल रूप से तुलना करें। यदि आपको इसकी आवश्यकता हो तो आप प्रक्षेपण के लिए LINQ का उपयोग ऑब्जेक्ट्स के लिए कर सकते हैं। –

+0

निश्चित रूप से, लेकिन आप यह नियंत्रित नहीं कर सकते कि कैसे 'संग्रह। निकालें (इकाई) तुलना करता है। यह कैसे असफल हो सकता है यह देखने के लिए नीचे दी गई मेरी पोस्ट में नमूना देखें। – TheCloudlessSky

5

हाँ!

आपको Equals और GetHashCode ओवरराइड करना चाहिए। लेकिन, आप मूल्य समानता (Name == other.Name && Age == other.Age) कर रहे हैं, तो आपको पहचान समानता करनी चाहिए!

यदि आप नहीं करते हैं, तो आप वास्तविक इकाई के साथ किसी इकाई की प्रॉक्सी की तुलना करने में अधिकतर दौड़ेंगे और यह डीबग करने के लिए दुखी होगा। उदाहरण के लिए:

public class Blog : EntityBase<Blog> 
{ 
    public virtual string Name { get; set; } 

    // This would be configured to lazy-load. 
    public virtual IList<Post> Posts { get; protected set; } 

    public Blog() 
    { 
     Posts = new List<Post>(); 
    } 

    public virtual Post AddPost(string title, string body) 
    { 
     var post = new Post() { Title = title, Body = body, Blog = this }; 
     Posts.Add(post); 
     return post; 
    } 
} 

public class Post : EntityBase<Post> 
{ 
    public virtual string Title { get; set; } 
    public virtual string Body { get; set; } 
    public virtual Blog Blog { get; set; } 

    public virtual bool Remove() 
    { 
     return Blog.Posts.Remove(this); 
    } 
} 

void Main(string[] args) 
{ 
    var post = session.Load<Post>(postId); 

    // If we didn't override Equals, the comparisons for 
    // "Blog.Posts.Remove(this)" would all fail because of reference equality. 
    // We'd end up be comparing "this" typeof(Post) with a collection of 
    // typeof(PostProxy)! 
    post.Remove(); 

    // If we *didn't* override Equals and *just* did 
    // "post.Blog.Posts.Remove(post)", it'd work because we'd be comparing 
    // typeof(PostProxy) with a collection of typeof(PostProxy) (reference 
    // equality would pass!). 
} 

यहाँ यदि आप के रूप में int का उपयोग कर रहे एक उदाहरण आधार वर्ग है अपने Id (जो भी any identity type को निकाला जा सकता है):

public abstract class EntityBase<T> 
    where T : EntityBase<T> 
{ 
    public virtual int Id { get; protected set; } 

    protected bool IsTransient { get { return Id == 0; } } 

    public override bool Equals(object obj) 
    { 
     return EntityEquals(obj as EntityBase<T>); 
    } 

    protected bool EntityEquals(EntityBase<T> other) 
    { 
     if (other == null) 
     { 
      return false; 
     } 
     // One entity is transient and the other is not. 
     else if (IsTransient^other.IsTransient) 
     { 
      return false; 
     } 
     // Both entities are not saved. 
     else if (IsTransient && other.IsTransient) 
     { 
      return ReferenceEquals(this, other); 
     } 
     else 
     { 
      // Compare transient instances. 
      return Id == other.Id; 
     } 
    } 

    // The hash code is cached because a requirement of a hash code is that 
    // it does not change once calculated. For example, if this entity was 
    // added to a hashed collection when transient and then saved, we need 
    // the same hash code or else it could get lost because it would no 
    // longer live in the same bin. 
    private int? cachedHashCode; 

    public override int GetHashCode() 
    { 
     if (cachedHashCode.HasValue) return cachedHashCode.Value; 

     cachedHashCode = IsTransient ? base.GetHashCode() : Id.GetHashCode(); 
     return cachedHashCode.Value; 
    } 

    // Maintain equality operator semantics for entities. 
    public static bool operator ==(EntityBase<T> x, EntityBase<T> y) 
    { 
     // By default, == and Equals compares references. In order to 
     // maintain these semantics with entities, we need to compare by 
     // identity value. The Equals(x, y) override is used to guard 
     // against null values; it then calls EntityEquals(). 
     return Object.Equals(x, y); 
    } 

    // Maintain inequality operator semantics for entities. 
    public static bool operator !=(EntityBase<T> x, EntityBase<T> y) 
    { 
     return !(x == y); 
    } 
} 
+1

यदि एक क्षणिक इकाई के पास 'गेटहाशकोड' लिया जाता है और गैर-क्षणिक हो जाता है, तो यह किसी अन्य इकाई के बराबर तुलना कर सकता है, जिसकी हानिकारक होने पर उसका हैश कोड नहीं लिया गया था, लेकिन इसका हैश कोड अन्य इकाई के बराबर नहीं होगा।किसी भी समय एक वस्तु किसी चीज के बराबर हो जाती है जो पहले नहीं थी, उसके हैश कोड को अन्य ऑब्जेक्ट के हैश कोड के बराबर होना चाहिए, और जब भी कोई वस्तु अस्तित्व में आती है जो किसी अन्य के बराबर होती है जिसका हैश लिया गया है, तो इसके हैश को बराबर होना चाहिए दूसरी वस्तु है। 'ConcurrentDictionary ' और ... – supercat

+1

... की आवश्यकता हो सकती है ... प्रत्येक आईडी एंटीटीबेस 'उस आईडी से जुड़े 'ऑब्जेक्ट' का संदर्भ रखें; यदि किसी इकाई से पहले 'GetHashCode' को बुलाया जाता है, तो यह' ऑब्जेक्ट 'उत्पन्न कर सकता है जो ऑब्जेक्ट जारी होने पर प्राप्त होने वाली आईडी से संबद्ध होगा। इसके बाद वह उस ऑब्जेक्ट के 'गेटहाशकोड' मान का उपयोग अपने आप के रूप में कर सकता है, और भविष्य की संस्थाएं जिनके पास अंततः प्राप्त होने वाले क्षणिक आईडी को पहचान पहचान टोकन मिल सकता है। समय-समय पर तालिका को उन प्रविष्टियों से साफ़ करना होगा जिनकी 'वीक रेफरेंस' की मृत्यु हो गई थी। – supercat

+0

@supercat क्या आप जो प्रस्ताव दे रहे हैं उसका एक उदाहरण तैयार करना चाहते हैं? मेरे ऊपर कार्यान्वयन एनएच लेखों की सामान्य सिफारिश है। क्या आप एक त्वरित नमूना भी प्रदान कर सकते हैं कि यह कैसे असफल हो सकता है? धन्यवाद! – TheCloudlessSky

संबंधित मुद्दे