См. http://fabiomaulo.blogspot.com/2009/09/nhibernate-tree-re-parenting.html
По сути, это сводится к следующему ... Вам нужно определить собственный тип коллекции для NHibernate, который заново определяет, что значит быть сиротой.Поведение NHibernate по умолчанию состоит в том, чтобы сделать так, как вы обнаружили - считать ребенка сиротой, если он был удален из родительского.Вместо этого вам нужен NHibernate, чтобы проверить ребенка, чтобы увидеть, был ли он назначен новому родителю.По умолчанию NHibernate не делает этого, потому что для этого требуется дополнительная информация о сопоставлении «один ко многим» - ему нужно знать имя соответствующего свойства «многие к одному» у дочернего элемента.
ИзменитьStorage
отображение выглядит так:
<class name="Storage">
<bag name="Boxes" cascade="all-delete-orphan" inverse="true" collection-type="StorageBoxBag">
<key column="Storage_Id" />
<one-to-many class="Box" />
</bag>
</class>
Определите новый тип с именем StorageBoxBag
(обратите внимание - этот код написан для NHibernate 2.1 - если вы используете NH3, возможно, вам придется немного его настроить):
public class StorageBoxBag : IUserCollectionType
{
public object Instantiate(int anticipatedSize)
{
return new List<Box>();
}
public IPersistentCollection Instantiate(ISessionImplementor session, ICollectionPersister persister)
{
return new PersistentStorageBoxBag(session);
}
public IPersistentCollection Wrap(ISessionImplementor session, object collection)
{
return new PersistentStorageBoxBag(session, (IList<Box>)collection);
}
public IEnumerable GetElements(object collection)
{
return (IEnumerable)collection;
}
public bool Contains(object collection, object entity)
{
return ((IList<Box>)collection).Contains((Box)entity);
}
public object IndexOf(object collection, object entity)
{
return ((IList<Box>) collection).IndexOf((Box) entity);
}
public object ReplaceElements(object original, object target, ICollectionPersister persister, object owner, IDictionary copyCache, ISessionImplementor session)
{
var result = (IList<Box>)target;
result.Clear();
foreach (var box in (IEnumerable)original)
result.Add((Box)box);
return result;
}
}
... и новый тип с именем PersistentStorageBoxBag
:
public class PersistentStorageBoxBag: PersistentGenericBag<Box>
{
public PersistentStorageBoxBag(ISessionImplementor session)
: base(session)
{
}
public PersistentStorageBoxBag(ISessionImplementor session, ICollection<Box> original)
: base(session, original)
{
}
public override ICollection GetOrphans(object snapshot, string entityName)
{
var orphans = base.GetOrphans(snapshot, entityName)
.Cast<Box>()
.Where(b => ReferenceEquals(null, b.CurrentStorage))
.ToArray();
return orphans;
}
}
В методе GetOrphans
происходит магия.Мы просим у NHibernate список Box
es, которые он считает сиротами, а затем фильтруем его до набора Box
es, которые фактически являются сиротами.