这个问题主要基于文章NHibernate – Automatic change tracking for aggregate roots in DDD scenarios
虽然文章中的逻辑似乎很合理,但我还没有找到涵盖所有用例的实现解决方案。 这个问题似乎与文章
中的以下段落有关这里有一个小问题,我们可能会在这里为每个事务生成多个更新,但我并不担心这一点,解决起来相当简单(通过跟踪实体而不更新,如果我们已经更新了当前的交易),所以我会留给你。
在本文之后,每当我们更新聚合根目录中的相关实体时,我们就会强制进行版本更新。但是,如果聚合根和相关实体都是“脏”,则会导致聚合根的双重更新。这导致nhibernate崩溃,因为默认情况下从脏聚合根触发的第二个版本更新期望版本与从db加载的版本相同。
我试图检查'PreInsertEventListener'和'PreUpdateEventListener',检查更新相关实体时聚合根是否脏。如果是这种情况,则忽略强制更新版本。
public bool OnPreUpdate(PreUpdateEvent updateEvent)
{
var rootFinder = updateEvent.Entity as ICanFindMyAggregateRoot;
if (rootFinder == null)
return false;
if (!updateEvent.Session.IsAggregateRootDirty(rootFinder.MyRoot))
{
updateEvent.Session.Lock(rootFinder.MyRoot, LockMode.Force);
}
return false;
}
public static class SessionExtensions
{
public static bool IsAggregateRootDirty(this ISession session, IAggregateRoot entity)
{
ISessionImplementor sessionImplementation = session.GetSessionImplementation();
IPersistenceContext persistenceContext = sessionImplementation.PersistenceContext;
IEntityPersister entityPersister = sessionImplementation.GetEntityPersister(null, entity);
EntityEntry entityEntry = persistenceContext.GetEntry(entity);
if ((entityEntry == null) && (entity is INHibernateProxy))
{
INHibernateProxy proxy = entity as INHibernateProxy;
object obj = sessionImplementation.PersistenceContext.Unproxy(proxy);
entityEntry = sessionImplementation.PersistenceContext.GetEntry(obj);
}
object[] oldState = entityEntry.LoadedState;
object[] currentState = entityPersister.GetPropertyValues(entity, sessionImplementation.EntityMode);
int[] findDirty = entityEntry.Persister.FindDirty(currentState, oldState, entity, sessionImplementation);
var hasDirtyCollection = currentState.OfType<IPersistentCollection>().Any(x => x.IsDirty);
return (findDirty != null) || hasDirtyCollection;
}
}
这个解决方案似乎确实有效,尽管我还需要用更少的用例来测试它。但是,我觉得这个解决方案有点沉重,希望能够提供更多解决方案。 有没有办法检测天气版本已经在同一个交易中更新或将会更新,或者跟踪交易集中实体的简单方法是否更新了版本。
感谢。