title: problem with NHibernate one-to-many relationship Collection with cascade
body: <p>I have AssetGroup entity with has a one-to-many relation with Asset entity. There is a Entity base class which overrides Equals and GetHashCode . I am following the example of <a href="http://www.nhforge.org/doc/nh/en/index.html#example-parentchild" rel="nofollow">ch 20 parent child</a></p>
  
  <pre><code>&lt;?xml version="1.0" encoding="utf-8" ?&gt;
  &lt;hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
                     assembly="TestNHibernate"
                     namespace="TestNHibernate.Models" auto-import="true"&gt;
    &lt;class name="AssetGroup"&gt;
      &lt;id name="Id" column="Id" type="guid"&gt;
        &lt;generator class="guid"&gt;&lt;/generator&gt;
      &lt;/id&gt;
      &lt;property name="Name" type="string" not-null="true"/&gt;
      &lt;set name="Assets" cascade="all" inverse="true" access="field.camelcase-underscore" lazy="true"&gt;
        &lt;key column="AssetGroupID"/&gt;
        &lt;one-to-many class="Asset"/&gt;
      &lt;/set&gt;
    &lt;/class&gt;
  &lt;/hibernate-mapping&gt;
  
  &lt;?xml version="1.0" encoding="utf-8" ?&gt;
  &lt;hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
                     assembly="TestNHibernate"
                     namespace="TestNHibernate.Models" auto-import="true"&gt;
    &lt;class name="Asset"&gt;
      &lt;id name="Id" column="Id" type="guid"&gt;
        &lt;generator class="guid"&gt;&lt;/generator&gt;
      &lt;/id&gt;
      &lt;property name="Name" type="string" not-null="true"/&gt;
      &lt;many-to-one name="AssetGroup" column="AssetGroupID" cascade="all" lazy="false"/&gt;
  
    &lt;/class&gt;
  &lt;/hibernate-mapping&gt;
  </code></pre>
  
  <p>the code as folloow:</p>
  
  <pre><code>public class AssetGroup : Entity&lt;Guid&gt;
  {
      public AssetGroup()
      {
          this._assets = new HashedSet&lt;Asset&gt;();
      }
  
  
      virtual public string Name { get; set; }
  
      private ISet&lt;Asset&gt; _assets;
      virtual public ISet&lt;Asset&gt; Assets
      {
          get { return _assets; }
          protected set { _assets = value; }
      }
  
      virtual public bool AddAsset(Asset asset)
      {
          if (asset != null &amp;&amp; _assets.Add(asset))
          {
              asset.SetAssetGroup(this);
              return true;
          }
          return false;
      }
  
      virtual public bool RemoveAsset(Asset asset)
      {
          if (asset != null &amp;&amp; _assets.Remove(asset))
          {
              asset.SetAssetGroup(null);
              return true;
          }
          return false;
      }
   }
  
  public class AssetGroup : Entity&lt;Guid&gt;
  {
      public AssetGroup()
      {
          this._assets = new HashedSet&lt;Asset&gt;();
      }
  
      virtual public string Name { get; set; }
  
      private ISet&lt;Asset&gt; _assets;
      virtual public ISet&lt;Asset&gt; Assets
      {
          get { return _assets; }
          protected set { _assets = value; }
      }
  
      virtual public bool AddAsset(Asset asset)
      {
          if (asset != null &amp;&amp; _assets.Add(asset))
          {
              asset.SetAssetGroup(this);
              return true;
          }
          return false;
      }
  
      virtual public bool RemoveAsset(Asset asset)
      {
          if (asset != null &amp;&amp; _assets.Remove(asset))
          {
              asset.SetAssetGroup(null);
              return true;
          }
          return false;
      }
  }
  </code></pre>
  
  <p>My TestCode is as follow :</p>
  
  <pre><code>[TestMethod]
  public void Can_Use_ISession()
  {
      ISession session = TestConfig.SessionFactory.GetCurrentSession();
      var ag = new AssetGroup { Name = "NHSession" };
      session.Save(ag);
  
      var a1 = new Asset { Name = "s1" };
      var a2 = new Asset { Name = "s2" };
  
      a1.SetAssetGroup(ag);
      a2.SetAssetGroup(ag);
  
      session.Flush();
  
      Assert.IsTrue(a1.Id != default(Guid)); // ok
      Assert.IsTrue(a2.Id != default(Guid)); // ok
  
      var enumerator = ag.Assets.GetEnumerator();
      enumerator.MoveNext();
      Assert.IsTrue(ag.Assets.Contains(enumerator.Current));  // failed
  
      Assert.IsTrue(ag.Assets.Contains(a1));  // failed
      Assert.IsTrue(ag.Assets.Contains(a2));  // failed 
  
      var agRepo2 = new NHibernateRepository&lt;AssetGroup&gt;(TestConfig.SessionFactory, new QueryFactory(TestConfig.Locator));
      Assert.IsTrue(agRepo2.Contains(ag)); // ok
      var ag2 = agRepo2.FirstOrDefault(x =&gt; x.Id == ag.Id);
      Assert.IsTrue(ag2.Assets.FirstOrDefault(x =&gt; x.Id == a1.Id) != null); // ok
      Assert.IsTrue(ag2.Assets.FirstOrDefault(x =&gt; x.Id == a2.Id) != null); // ok
  
      var aa1 = session.Get&lt;Asset&gt;(a1.Id);
      var aa2 = session.Get&lt;Asset&gt;(a2.Id);
      Assert.IsTrue(ag2.Assets.Contains(aa1));  // failed
      Assert.IsTrue(ag2.Assets.Contains(aa2));  // failed
  
  }
  </code></pre>
  
  <p>My Entity base class is here:</p>
  
  <pre><code>public abstract class Entity&lt;Tid&gt; : IEquatable&lt;Entity&lt;Tid&gt;&gt;
  {
      [HiddenInput(DisplayValue = false)]
      public virtual Tid Id { get; protected set; }
  
      public override bool Equals(object obj)
      {
          if (obj == null)
              return base.Equals(obj);
          return Equals(obj as Entity&lt;Tid&gt;);
      }
  
      public static bool IsTransient(Entity&lt;Tid&gt; obj)
      {
          return obj != null &amp;&amp; Equals(obj.Id, default(Tid));
      }
  
      private Type GetUnproxiedType()
      {
          return GetType();
      }
  
      public virtual bool Equals(Entity&lt;Tid&gt; other)
      {
          if (ReferenceEquals(this, other))
              return true;
          if (!IsTransient(this) &amp;&amp; !IsTransient(other) &amp;&amp; Equals(Id, other.Id))
          {
              var otherType = other.GetUnproxiedType();
              var thisType = GetUnproxiedType();
              return thisType.IsAssignableFrom(otherType) || otherType.IsAssignableFrom(thisType);
          }
          return false;
      }
  
      public override int GetHashCode()
      {
          if (Equals(Id, default(Tid)))
          {
              return base.GetHashCode();
          }
          else
          {
              return Id.GetHashCode();
          }
      }
  
  }
  </code></pre>
  
  <p>I have commented which parts have failed in the code . Please help. It seems entities which are saved by cascading is not compatible with ICollection Contains/Remove . Asset a1 a2 are saved and they are inside the parent's Collection . For example I can find them by Linq FirstOrDefault . But the Collection's Contains and Remove will fail to find them . I notice the Collection use GetHashCode while Contains() or Remove() are called.</p>