Design patterns 如何实际处理UnitOfWork模式
UoW实际应该处理什么 在我看来,UoW不应该处理提交和回滚。它应该只提供这样做的方法,并且应该只负责跟踪即将提交的对象上的更改,以便如果这些对象处于不一致的状态或某些内容发生了更改,那么事务应该失败 我看到UoW的方式是这样的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>
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();
}
}