2011-08-25 67 views
2

Nhibernate強制您使用Iesi Set,而不是Net 4 ISet接口。在下面的代碼片段中,我檢查一個iesi集合是否包含一個項目:Nhibernate iesicollection包含返回false

public virtual void Remove(Substance substance) 
    { 
     var test = _substances.First() == substance; 

     if (!_substances.Contains(substance)) return; 

     _substances.Remove(substance); 
     substance.SubstanceGroup = null; 
    } 

變量_substances引用一個HashedSet。我已經添加了測試變量,只是將代碼作爲臨時度量來檢查。 我重寫這樣的Equals方法:

public override int GetHashCode() 
    { 
     return Equals(Id, default(TId)) ? base.GetHashCode() : Id.GetHashCode(); 
    } 

這將導致返回ID(GUID)作爲哈希的項目。 如果我檢查在調試器我得到以下結果:

test 
true 
_substances.Contains(substance) 
false 
_substances.First().GetHashCode() 
-2974953 
substance.GetHashCode() 
-2974953 

怎麼會是完全相同的對象不使用含有該集合的方法集合中發現的?我甚至可以在調試器中執行此操作:

_substances.Contains(_substances.First()) 
false 

顯然,_substances.Remove(物質)也不起作用。經過一些額外的研究後,我發現NH用它自己的Persistent Generic集取代了集合。使用該組時,會出現問題。如果我從該集合中檢索一個項目,並且在同一集合上調用Contains,它總是返回false。我重寫了GetHashCode和Equals,甚至在Equals方法中返回true。

+0

你是否也覆蓋了Equals方法?像http://blog.visualt4.com/2009/03/nhibernate-why-override-gethashcode-and.html – Bas

+0

是的,我甚至把它的真相,沒有任何結果。這是我與Nhibernate的另一個拉毛問題。 – halcwb

回答

3

您的Equals和GetHashCode實現有問題,因爲我向您保證Iesi ISet集合可以正常工作。它被PersistentGenericSet取代的原因是ISet只是一個接口,集合必須由一個具體類型替換。沒有更多的代碼,很難看到問題出在哪裏,所以我在下面粘貼了一個更好的平等實現。我能看到的一個問題是,哈希碼會在Id被分配後發生改變,我的版本通過緩存哈希碼來處理哈希碼。

public class Substance 
{ 
    private int? _cachedHashCode; 

    public Substance() 
    { 
     Id = Guid.Empty; 
    } 

    public Substance(Guid id) 
    { 
     Id = id; 
    } 

    public Guid Id { get; set; } 

    public bool IsTransient 
    { 
     get { return Id == Guid.Empty; } 
    } 

    public bool Equals(Substance other) 
    { 
     if (IsTransient^other.IsTransient) 
     { 
      return false; 
     } 
     if (IsTransient && other.IsTransient) 
     { 
      return ReferenceEquals(this, other); 
     } 
     return other.Id.Equals(Id); 
    } 

    public override bool Equals(object obj) 
    { 
     if (obj == null || obj.GetType() != GetType()) 
     { 
      return false; 
     } 
     var other = (Substance)obj; 
     return Equals(other); 
    } 

    public override int GetHashCode() 
    { 
     if (!_cachedHashCode.HasValue) 
     { 
      _cachedHashCode = IsTransient ? base.GetHashCode() : Id.GetHashCode(); 
     } 
     return _cachedHashCode.Value; 
    } 
} 

public class Mixture 
{ 
    public Mixture() 
    { 
     Substances = new HashedSet<Substance>(); 
    } 

    public ISet<Substance> Substances { get; set; } 
} 

public class Tests 
{ 
    [Test] 
    public void set_contains_transient_substance() 
    { 
     var mixture = new Mixture(); 
     var s1 = new Substance(); 
     mixture.Substances.Add(s1); 
     Assert.IsTrue(mixture.Substances.Contains(s1)); 
    } 

    [Test] 
    public void set_contains_persistent_substance() 
    { 
     var id = Guid.NewGuid(); 
     var mixture = new Mixture(); 

     var s1 = new Substance(id); 
     mixture.Substances.Add(s1); 

     var s2 = new Substance(id); 
     // these were created with the same id so hash code is not cached 
     // and id equality is used 
     Assert.IsTrue(mixture.Substances.Contains(s2)); 
    } 

    [Test] 
    public void remove_substance() 
    { 
     var id = Guid.NewGuid(); 
     var mixture = new Mixture(); 

     var s1 = new Substance(id); 
     mixture.Substances.Add(s1); 

     var s2 = new Substance(id); 
     mixture.Substances.Remove(s2); 
     Assert.IsTrue(mixture.Substances.Count() == 0); 
    } 

    [Test] 
    public void hash_code_is_cached() 
    { 
     var s1 = new Substance(Guid.NewGuid()); 
     var s2 = new Substance(Guid.NewGuid()); 

     var mixture = new Mixture(); 
     mixture.Substances.Add(s1); 

     Assert.IsFalse(mixture.Substances.Contains(s2)); 
     // assign s1 id to s2, s2 hashcode is cached so they are not equal 
     s2.Id = s1.Id; 
     Assert.IsFalse(mixture.Substances.Contains(s2)); 
    } 

} 
+0

這樣做的竅門,非常感謝。在我的基類中,我實現了哈希碼的緩存。 – halcwb

+1

但是,一個重要的警告是,您的解決方案意味着標識符由應用程序設置,而不是由NH設置。不幸的是,你錯過了NH這樣做的一些重要功能。 – halcwb