2011-02-18 4 views
3

У меня есть 2 класса, которые обрабатываются NHibernate: AssetGroup, Asset У AssetGroup есть коллекция ISet _assets. Конструктор AssetGroup будет сказатьnhibernate Iesi ISet не удаляется()

_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 может найти актив (targe), который должен быть RemoveAsset'ed. Как ни странно, когда я прошу _assets удалить цель. Не удается удалить и вернуть false. Кроме того, если я спрашиваю _assets.Contains (цель) .. это также возвращает ложь .. даже если цикл Еогеаспа в RemoveAsset может найти цель ...

два NHibernate отображения является

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

Может кто-нибудь мне помочь?

ответ

1

Вы уверены, что это фактический код? Мне кажется, что даже если вы переопределите Equals и GetHashCode в некотором некорректном порядке, как только вы обнаружите, что Asset и target назначены объектом из _assets, метод Remove не должен прерываться при вызове с целью, поскольку он определенно содержится в набор. Я сделал короткий тест, и набор вел себя так, как ожидалось.

+0

Я использовал базовый класс сущностей, из которого все else получается. Я пересмотрю свою публикацию с помощью класса Entity. Я поставил точки останова в коде, и он запускает мой GetHashCode(), но не переопределенный Equals (..). Также я замечаю, что, хотя я специфически HasSet <> как Asset ctor, указанным типом является NHibernate.Collection.Generic.PersistentGenericSet , который мне неизвестен. –

+0

У меня возникли проблемы с отправкой кода xml. Кажется, что он может отображать только первую строку, но когда я редактирую сообщение, я вижу полный список кодов. –

+0

Я скопировал ваш код в единичный тест и выполнил его, тест прошел. В тесте я создал 3 Assets, добавил их в AssetGroup, а затем создал 4-й Asset с тем же именем и идентификатором, что и первый из 3-х активов. RemoveAset() возвращает true, и Asset удаляется из коллекции, если я передаю вновь созданный 4-й актив методу. Пожалуйста, сделайте единичный тест и проверьте, прошел ли ваш код такой тест. Если это так, может возникнуть проблема с созданным типом коллекции NHibernate или что-то, что мне сейчас не хватает. Но код, который вы опубликовали, выглядит хорошо. –

1

Я думаю, что я столкнулся с той же проблемой, и «проблема» состояла в том, что я добавил элемент в HashedSet и после этого изменил его (чтобы присвоить идентификаторы), изменив результат GetHashCode.

Я думаю, что это означает, что объект оказался в другом ковше во внутреннем словаре, следовательно Содержит возвращаемый false.

+0

Я сталкиваюсь с такой же проблемой, и ваш ответ звучит так, как будто это имеет большой смысл. Итак, есть ли способ обхода/лучшего способа сделать это? –

0

У меня почти идентичная реализация вашего объекта Entity объекта (мы, должно быть, прочитали ту же книгу: D).

Как заявляет Бруно, проблема заключается в том, что 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); 
Смежные вопросы