У меня есть объект 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
}
Базовый класс My 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 ().