Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/github/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Design patterns 如何实际处理UnitOfWork模式_Design Patterns_Unit Of Work - Fatal编程技术网

Design patterns 如何实际处理UnitOfWork模式

Design patterns 如何实际处理UnitOfWork模式,design-patterns,unit-of-work,Design Patterns,Unit Of Work,UoW实际应该处理什么 在我看来,UoW不应该处理提交和回滚。它应该只提供这样做的方法,并且应该只负责跟踪即将提交的对象上的更改,以便如果这些对象处于不一致的状态或某些内容发生了更改,那么事务应该失败 我看到UoW的方式是这样的 public interface IUnitOfWork : IDisposable { IAtomicTransaction BeginTransaction(); Task<object> SaveAsync<TEntity>

UoW实际应该处理什么

在我看来,UoW不应该处理提交和回滚。它应该只提供这样做的方法,并且应该只负责跟踪即将提交的对象上的更改,以便如果这些对象处于不一致的状态或某些内容发生了更改,那么事务应该失败

我看到UoW的方式是这样的

public interface IUnitOfWork : IDisposable
{
    IAtomicTransaction BeginTransaction();

    Task<object> SaveAsync<TEntity>(TEntity entity);

    Task UpdateAsync<TEntity>(TEntity entity);

    Task RemoveAsync<TEntity>(TEntity entity);
}
以这篇文章为例(不仅是这篇,还有很多类似的文章)

如果您查看一下,您会发现它在存储库中使用ISession,我发现这是一个错误,因为它将直接将存储库(您的业务)链接到NHibernate的ISession。UoW不应该承担这个责任吗?您是否应该因为更改了框架而开始更改业务实现? UoW不应该充当适配器吗?类似于反腐败层吗?

UoW不仅仅是一个事务。以下引述自:

工作单元跟踪您在业务事务期间所做的可能影响数据库的一切。完成后,它会计算出由于您的工作而需要修改数据库的所有操作

它应当:

  • 为您的存储库提供上下文
    允许从此UoW实例创建存储库,或允许将此UoW实例注入存储库。我喜欢第一种方法。所有具有
    内部
    构造函数和UoW中某些类似工厂的方法的存储库都会创建存储库
  • 跟踪此上下文中的更改
    这是一个复杂的主题,但为了简单起见,让我们将其限制为数据库事务。许多orm以更好的方式处理这个问题。可以通过多种方式跟踪实体对象的状态。维护变更列表,维护实体的状态(脏或不脏),或维护实体的原始副本,并在末尾将其与最终副本进行比较等
  • 刷新/不刷新在此上下文中所做的更改
    这与上面的一点有关。根据跟踪,确定需要将哪些更改刷新到存储中。一些UoW实现还支持自动刷新,其中UoW自动决定何时刷新更改。如果一切顺利,变化就会被刷新;如果有问题,就不要冲洗。同样,为了简单起见,让我们将此限制为数据库事务。对于详细的实现,使用一些好的ORM是更好的解决方案
  • 创建和清理资源
    UoW实例应(自动或手动)创建执行操作所需的资源,并在不再需要时清理这些资源

  • 方法
    CreateRepository
    在此UoW下创建存储库的实例。这样,您可以在多个存储库中共享相同的UoW。这样,一个DB事务可以分布在多个存储库中。另一种选择是在存储库中注入UoW,如图所示

    这种方法的问题在于,它不强制UoW。何时(或是否)启动事务由调用方决定


    我能想象的UoW的另一个迷你版本(强制UoW)如下所示:

    public sealed class UoWSession
    {
        public UoWSession()
        {
            //Open connection here
            //Begin transaction here
        }
    
        IRepository CreateRepository(....)
        {
            //Create and return the requested repository instance here
        }
    
        void Commit()
        {
            transaction.Commit();
        }
    
        void Dispose()
        {
            //If transaction is not commited, rollback it here.
            //Cleanup resources here.
        }
    }
    
    如果不使用ORM,您必须公开一些告诉您一切正常的信息。上述实现使用了
    Commit
    方法。
    可能有一个简单的属性,比如说
    IsAllWell
    ,默认情况下它是
    false
    ,调用代码会显式地设置它。然后,您的
    Dispose
    方法根据属性提交或回滚事务。在这种情况下,您不需要公开
    Commit
    方法,因为您正在标记上内部处理它

    既然你已经编辑了你的问题,我必须改变我的回答方式;因此,第二个答案。我的书仍然很有价值(希望如此)

    UoW应自动确定需要刷新的更改(如果有)

    上述方法可能是也可能不是UoW的一部分。UoW的许多实现都公开了这些。公开这些信息的缺点是,事务处理成为调用方的责任;不是你们班。另外一点是,调用者可以更好地控制流程

    如果你想绕过这个缺点,请参阅我的第一个答案中的备选方案


    顺便说一下,这个话题本身是基于观点的。如何实现UoW和存储库是个人的设计决策。如果您真的热衷于执行正确的(UO),请考虑在代码中直接使用一些高级ORM绕过UW包装器。< /P>当我调用<代码> StistTraceActhon()/代码>两次时会发生什么?我的想法是,我想保护企业免受外部因素的影响。如果在某一点上会有变化,就永远不应该在业务层面上进行。唯一被触动的部分是UoW,它应该确保真相的唯一来源。我尝试一种解决方案,在我的业务中不直接引用框架的任何部分。SqlConnectionProvider应抽象ISession、IDbConnection等,而IAtomicTransaction应抽象ITransaction、IDBCTransaction等。因此,所有访问都将使用SqlConnectionProvider和IAtomicTransaction完成。当然,但是这个问题仍然有效-您不能保证它将始终并且仅由您处理代码-当调用两次
    StartTransaction()
    时会发生什么?
    interface IUnitOfWork : IDisposable
    {
        IDbConnection Connection { get; }
        IDbTransaction Transaction { get; }
        void Begin();
        void Commit();
        void Rollback();
    
        IRepository CreateRepository(....);
    }
    
    public sealed class UoWSession
    {
        public UoWSession()
        {
            //Open connection here
            //Begin transaction here
        }
    
        IRepository CreateRepository(....)
        {
            //Create and return the requested repository instance here
        }
    
        void Commit()
        {
            transaction.Commit();
        }
    
        void Dispose()
        {
            //If transaction is not commited, rollback it here.
            //Cleanup resources here.
        }
    }
    
    IAtomicTransaction BeginTransaction();
    void Commit();
    void Rolleback();
    
    Task<object> SaveAsync<TEntity>(TEntity entity);
    Task UpdateAsync<TEntity>(TEntity entity);
    Task RemoveAsync<TEntity>(TEntity entity);
    
    public interface IUnitOfWork : IDisposable
    {
        void Flush();
    }
    
    public sealed class UnitOfWork : IUnitOfWork
    {
        public UnitOfWork()
        {
            session = SessionFactroyHelper.CreateSession();
            transaction = session.BeginTransaction();
        }
    
        ISession session = null;
        ITransaction transaction = null;
    
        void IUoWSession.Flush()
        {
            transaction.Commit();
        }
    
        void IDisposable.Dispose()
        {
            transaction.Dispose();
            transaction = null;
            session.Dispose();
            session.Dispose();
        }
    }