да, Asset.SetAssetGroup (ag) действительно добавляет актив в коллекцию группы активов. По какой-то неизвестной причине nhibernate Isei HashSet's Contains не использует переопределение моего Entity <Tid> Equals (). И если я не сессию. Refresh (ag), вызов Contains () возвращает false. Аналогично HashSet Remove (..) также завершится ошибкой и вернет false.

я есть сущность AssetGroup с имеет отношение один ко многим с сущностью актива. Существует базовый класс Entity, который переопределяет Equals и GetHashCode. Я следую примеруch 20 родительский ребенок

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
                   assembly="TestNHibernate"
                   namespace="TestNHibernate.Models" auto-import="true">
  <class name="AssetGroup">
    <id name="Id" column="Id" type="guid">
      <generator class="guid"></generator>
    </id>
    <property name="Name" type="string" not-null="true"/>
    <set name="Assets" cascade="all" inverse="true" access="field.camelcase-underscore" lazy="true">
      <key column="AssetGroupID"/>
      <one-to-many class="Asset"/>
    </set>
  </class>
</hibernate-mapping>

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
                   assembly="TestNHibernate"
                   namespace="TestNHibernate.Models" auto-import="true">
  <class name="Asset">
    <id name="Id" column="Id" type="guid">
      <generator class="guid"></generator>
    </id>
    <property name="Name" type="string" not-null="true"/>
    <many-to-one name="AssetGroup" column="AssetGroupID" cascade="all" lazy="false"/>

  </class>
</hibernate-mapping>

код следующим образом:

public class AssetGroup : Entity<Guid>
{
    public AssetGroup()
    {
        this._assets = new HashedSet<Asset>();
    }


    virtual public string Name { get; set; }

    private ISet<Asset> _assets;
    virtual public ISet<Asset> Assets
    {
        get { return _assets; }
        protected set { _assets = value; }
    }

    virtual public bool AddAsset(Asset asset)
    {
        if (asset != null && _assets.Add(asset))
        {
            asset.SetAssetGroup(this);
            return true;
        }
        return false;
    }

    virtual public bool RemoveAsset(Asset asset)
    {
        if (asset != null && _assets.Remove(asset))
        {
            asset.SetAssetGroup(null);
            return true;
        }
        return false;
    }
 }

public class AssetGroup : Entity<Guid>
{
    public AssetGroup()
    {
        this._assets = new HashedSet<Asset>();
    }

    virtual public string Name { get; set; }

    private ISet<Asset> _assets;
    virtual public ISet<Asset> Assets
    {
        get { return _assets; }
        protected set { _assets = value; }
    }

    virtual public bool AddAsset(Asset asset)
    {
        if (asset != null && _assets.Add(asset))
        {
            asset.SetAssetGroup(this);
            return true;
        }
        return false;
    }

    virtual public bool RemoveAsset(Asset asset)
    {
        if (asset != null && _assets.Remove(asset))
        {
            asset.SetAssetGroup(null);
            return true;
        }
        return false;
    }
}

Мой TestCode выглядит следующим образом:

[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<AssetGroup>(TestConfig.SessionFactory, new QueryFactory(TestConfig.Locator));
    Assert.IsTrue(agRepo2.Contains(ag)); // ok
    var ag2 = agRepo2.FirstOrDefault(x => x.Id == ag.Id);
    Assert.IsTrue(ag2.Assets.FirstOrDefault(x => x.Id == a1.Id) != null); // ok
    Assert.IsTrue(ag2.Assets.FirstOrDefault(x => x.Id == a2.Id) != null); // ok

    var aa1 = session.Get<Asset>(a1.Id);
    var aa2 = session.Get<Asset>(a2.Id);
    Assert.IsTrue(ag2.Assets.Contains(aa1));  // failed
    Assert.IsTrue(ag2.Assets.Contains(aa2));  // failed

}

Мой базовый класс Entity находится здесь:

public abstract class Entity<Tid> : IEquatable<Entity<Tid>>
{
    [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<Tid>);
    }

    public static bool IsTransient(Entity<Tid> obj)
    {
        return obj != null && Equals(obj.Id, default(Tid));
    }

    private Type GetUnproxiedType()
    {
        return GetType();
    }

    public virtual bool Equals(Entity<Tid> other)
    {
        if (ReferenceEquals(this, other))
            return true;
        if (!IsTransient(this) && !IsTransient(other) && 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();
        }
    }

}

Я прокомментировал, какие части потерпели неудачу в коде. Пожалуйста помоги. Кажется, что объекты, сохраненные каскадом, несовместимы с ICollection Contains / Remove. Актив a1 a2 сохранен и находится в родительской коллекции. Например, я могу найти их по Linq FirstOrDefault. Но Коллекция Содержит и Удалить не сможет найти их. Я замечаю, что Коллекция использует GetHashCode, когда вызываются Contains () или Remove ().

Ответы на вопрос(2)

Ваш ответ на вопрос