nhibernate Iesi ISet无法删除()

时间:2011-02-18 10:15:21

标签: nhibernate hashset

我有两个由NHibernate处理的类:AssetGroup,Asset AssetGroup有一个ISet _assets集合。 AssetGroup的构造函数会说

_assets = new HashSet<Asset>();

我有一些操作要添加,删除AssetGroup中的资产

    public abstract class Entity<Tid>
{
    public virtual Tid Id { get; protected set; }

    public override bool Equals(object 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 (other == null)
            return false;
        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();
        }
    }
}

///////////////////////////////////////


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

    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))
        {
            return true;
        }
        return false;
    }

    virtual public bool RemoveAsset(Asset asset)
    {
        Asset target = null;
        foreach (var a in _assets)
        {
            var x = a.GetHashCode();
            var b = a.Equals(asset);
            if (a.Equals(asset))
                target = a;
        }
        if (target == null)
            return false;
        if (asset != null && _assets.Remove(target))
        {
            return true;
        }
        return false;
    }

}

////////////////////////////////////////

public class Asset : Entity<int> 
{
    public Asset()
    {
        SecurityKey = Guid.NewGuid();
    }

    public virtual Guid SecurityKey { get; set; }

    virtual public int AssetGroupID { get { return (AssetGroup != null ? AssetGroup.Id : 0); } }

    virtual public string Name { get; set; }

    virtual public AssetGroup AssetGroup { get; set;}

    virtual public void SetAssetGroup(AssetGroup assetGroup)
    {
        AssetGroup prevRef = AssetGroup;
        if (prevRef == assetGroup)
            return;
        AssetGroup = assetGroup;
        if (prevRef != null)
            prevRef.Assets.Remove(this);
        if (assetGroup != null)
            assetGroup.Assets.Add(this);
    }
}

RemoveAsset无法删除资产。我有一个foreach来检查资产是否存在于_assets中。我把断点跟踪到它并且foreach循环可以找到要被删除的资产(目标)。奇怪的是,当我要求_assets删除目标时。 它无法删除并返回false。 此外,如果我问_assets.Contains(目标)..它也返回false ..即使RemoveAsset中的foreach循环可以找到目标......

两个nhibernate映射是

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
               assembly="MySystem.Domain"
               namespace="MySystem.Domain" auto-import="true">

                                  

                                                   

有人能帮助我吗?

3 个答案:

答案 0 :(得分:1)

你确定这是实际执行的代码吗?在我看来,即使你以某种错误的方式覆盖Equals和GetHashCode,只要你发现一个资产和目标被分配了来自_assets的对象,当使用目标调用时,Remove方法永远不会失败,因为它绝对包含在集。我做了一个简短的测试,并且该设置符合预期。

答案 1 :(得分:1)

我认为我刚遇到同样的问题,“问题”是我将项目添加到HashedSet中,之后 更改了它(分配ID),更改了GetHashCode的结果。

我认为这意味着该对象最终位于内部字典中的另一个存储桶中,因此包含返回false

答案 2 :(得分:0)

是的,我的基本实体对象的实现几乎相同(我们必须阅读同一本书:D)。

正如Bruno所说,问题在于GetHashCode返回不同​​的值(基础对象对象引用或主键值)。在大多数情况下,这对我来说不是问题,因为我很少在保存对象后更改它,但在某些情况下,如下所示,这可能会导致问题:

FuelTank newtank = new FuelTank();

// Below stores tank in the Tanks Set using the 
//objects reference identity (since it is a new object)
vessel.Tanks.Add(newtank); 

//returns true because newtank.Id has not changed (remove 
//uses Contains internally  to see if an object can be removed)
vessel.Tanks.Contains(newtank); 

//now newtank.Id changes because a primary key is 
//generated for it at this point
Repository.Save(vessel); 

// returns false because newtank is still stored under 
//its object reference in the set but its id is now the id of a PK
vessel.Tanks.Contains(newtank);