Начиная использовать Nhibernate для обеспечения устойчивости, обещая, что он уважает вашу модель домена, я попытался реализовать диспетчер отношений для своих объектов домена. По сути, чтобы СУХОЙ мой код в отношении управления двунаправленными отношениями один ко многим и многими ко многим, я решил, чтобы эти отношения управлялись отдельным классом. Когда установлено свойство «один ко многим» или «много к одному», запись для двух объектов создается в словаре, ключом является либо одна сторона со значением коллекции для хранения многих сторон, либо много сторон со значением одна сторона.
Отношение один ко многим для конкретной комбинации типов выглядит следующим образом:
public class OneToManyRelation<TOnePart, TManyPart> : IRelation<IRelationPart, IRelationPart>
where TOnePart : class, IRelationPart
where TManyPart : class, IRelationPart
{
private readonly IDictionary<TOnePart, Iesi.Collections.Generic.ISet<TManyPart>> _oneToMany;
private readonly IDictionary<TManyPart, TOnePart> _manyToOne;
public OneToManyRelation()
{
_manyToOne = new ConcurrentDictionary<TManyPart, TOnePart>();
_oneToMany = new ConcurrentDictionary<TOnePart, Iesi.Collections.Generic.ISet<TManyPart>>();
}
public void Set(TOnePart onePart, TManyPart manyPart)
{
if (onePart == null || manyPart == null) return;
if (!_manyToOne.ContainsKey(manyPart)) _manyToOne.Add(manyPart, onePart);
else _manyToOne[manyPart] = onePart;
}
public void Add(TOnePart onePart, TManyPart manyPart)
{
if (onePart == null || manyPart == null) return;
if (!_manyToOne.ContainsKey(manyPart)) _manyToOne.Add(manyPart, onePart);
else _manyToOne[manyPart] = onePart;
if (!_oneToMany.ContainsKey(onePart)) _oneToMany.Add(onePart, new HashedSet<TManyPart>());
_oneToMany[onePart].Add(manyPart);
}
public Iesi.Collections.Generic.ISet<TManyPart> GetManyPart(TOnePart onePart)
{
if (!_oneToMany.ContainsKey(onePart)) _oneToMany[onePart] = new HashedSet<TManyPart>();
return _oneToMany[onePart];
}
public TOnePart GetOnePart(TManyPart manyPart)
{
if(!_manyToOne.ContainsKey(manyPart)) _manyToOne[manyPart] = default(TOnePart);
return _manyToOne[manyPart];
}
public void Remove(TOnePart onePart, TManyPart manyPart)
{
_manyToOne.Remove(manyPart);
_oneToMany[onePart].Remove(manyPart);
}
public void Set(TOnePart onePart, Iesi.Collections.Generic.ISet<TManyPart> manyPart)
{
if (onePart == null) return;
if (!_oneToMany.ContainsKey(onePart)) _oneToMany.Add(onePart, manyPart);
else _oneToMany[onePart] = manyPart;
}
public void Clear(TOnePart onePart)
{
var list = new HashedSet<TManyPart>(_oneToMany[onePart]);
foreach (var manyPart in list)
{
_manyToOne.Remove(manyPart);
}
_oneToMany.Remove(onePart);
}
public void Clear(TManyPart manyPart)
{
if (!_manyToOne.ContainsKey(manyPart)) return;
if (_manyToOne[manyPart] == null) return;
_oneToMany[_manyToOne[manyPart]].Remove(manyPart);
_manyToOne.Remove(manyPart);
}
}
На многих сторонах фрагмент кода выглядит так:
public virtual SubstanceGroup SubstanceGroup
{
get { return RelationProvider.SubstanceGroupSubstance.GetOnePart(this); }
protected set { RelationProvider.SubstanceGroupSubstance.Set(value, this); }
}
С одной стороны, поэтому в данном случае SubstanceGroup фрагмент выглядит следующим образом:
public virtual ISet<Substance> Substances
{
get { return RelationProvider.SubstanceGroupSubstance.GetManyPart(this); }
protected set { RelationProvider.SubstanceGroupSubstance.Set(this, value); }
}
Просто используя мои доменные объекты, это отлично работает. В объекте предметной области мне просто нужно сослаться на абстрактную фабрику, которая получает соответствующее отношение, и я могу установить отношение с одной стороны, которая автоматически становится двунаправленной.
Однако, когда NH запускает проблему, я получаю дубликаты ключей в своих словарях. Каким-то образом NH устанавливает свойство отношения с нулевым значением (!) С новой копией (?) Объекта домена. Поэтому, когда объект домена сохраняется, у меня есть две записи этого объекта домена, например, многогранная часть отношения, т.е. словарь _manyToOne.
Эта проблема заставляет меня терять волосы, я не понимаю, что происходит ??