更改跟踪DDD中的聚合根

时间:2015-01-18 01:15:25

标签: nhibernate domain-driven-design

这个问题主要基于文章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;
        }
}

这个解决方案似乎确实有效,尽管我还需要用更少的用例来测试它。但是,我觉得这个解决方案有点沉重,希望能够提供更多解决方案。 有没有办法检测天气版本已经在同一个交易中更新或将会更新,或者跟踪交易集中实体的简单方法是否更新了版本。

感谢。

1 个答案:

答案 0 :(得分:-1)

我认为你正在寻找乐观并发。请参阅http://ayende.com/blog/3946/nhibernate-mapping-concurrency