Unit Of Work--工作单元(二)
回顾
上一篇我们根据工作单元的原理基于ADO.NET进行了简单的实现,但是当项目需求发生变化的时候,比如需要引入ORM框架又要兼容当前ADO.NET实现的方式时,先前的实现就无法满足这个需求了。
话就不多说了,我们就跟据当前的需求变化来重构工作单元吧。
重构UnitOfWork
首先我们看看原先实现的工作单元提取出来的接口,代码如下:
public interface IUnitOfWork { void RegisterAdd(string sql, params IDataParameter[] parameters); void RegisterSave(string sql, params IDataParameter[] parameters); void RegisterRemove(string sql, params IDataParameter[] parameters); void Comit(); }
由于需求需要兼容ORM和ADO.NET方式,而以上的接口仅仅支持ADO.NET的方式,因此接口需要改变,例如:
//其他代码省略 void RegisterAdd(object entity);
观察以上的修改会发现如果要满足需求,则需要判断是ADO.NET或者是ORM的操作,那么就有了两种不同的职责,这显然是不合理的,但是如果我们将ADO.NET和ORM还是让对应的数据层类去实现的话,就符合单一责任了,于是经过以上分析,就可以对以上的接口做进一步的修改了,大致代码如下:
//其他代码省略 void RegisterAdd(object entity, IUnitOfWorkRepository repository);
按照这个思路的话,这个IUnitOfWorkRepository的方法数量则会跟IUnitOfWork基本相同(没有Commit),一个是注册,而另一个则是实际的操作,因此接口代码则会跟第一次改为object的相同了,代码如下:
public interface IUnitOfWorkRepository { void ExecuteAdd(object entity); void ExecuteSave(object entity); void ExecuteRemove(object entity); }
有了以上的改变之后,就可以实现IUnitOfWork了,代码结构上还是跟SQLUnitOfWork类似的,差别是原先是使用一个List<SQLEntity>来存储所有的CUD操作,但是现在必须要区分出不同类型的操作,因此需要有分别存储CUD的容器,大致代码如下:
public class UnitOfWork : IUnitOfWork { private Dictionary<object, IUnitOfWorkRepository> m_addList = new Dictionary<object, IUnitOfWorkRepository>(); private Dictionary<object, IUnitOfWorkRepository> m_saveList = new Dictionary<object, IUnitOfWorkRepository>(); private Dictionary<object, IUnitOfWorkRepository> m_removeList = new Dictionary<object, IUnitOfWorkRepository>(); public void RegisterAdd(object entity, IUnitOfWorkRepository repository) { if (!this.m_addList.ContainsKey(entity)) this.m_addList.Add(entity, repository); } public void RegisterSave(object entity, IUnitOfWorkRepository repository) { if (!this.m_saveList.ContainsKey(entity)) this.m_saveList.Add(entity, repository); } public void RegisterRemove(object entity, IUnitOfWorkRepository repository) { if (!this.m_removeList.ContainsKey(entity)) this.m_removeList.Add(entity, repository); } public void Commit() { using (TransactionScope trans = new TransactionScope()) { foreach (var entity in this.m_addList.Keys) { this.m_addList[entity].ExecuteAdd(entity); } foreach (var entity in this.m_saveList.Keys) { this.m_saveList[entity].ExecuteSave(entity); } foreach (var entity in this.m_removeList.Keys) { this.m_removeList[entity].ExecuteRemove(entity); } trans.Complete(); } } }
到这里我们就将工作单元重构工作完成了,接下来就可以根据IUnitOfWorkRepository派生出基于ADO.NET和ORM的实现了。
重构SchoolRepository
首先我们先看一下重构后的代码:
class SchoolRepository : IRepository, IUnitOfWorkRepository { private IDbConnection m_connection = null; private IUnitOfWork m_uow = null; public SchoolRepository(IDbConnection connection, IUnitOfWork uow) { this.m_connection = connection; this.m_uow = uow; } public void Add(object entity) { this.m_uow.RegisterAdd(entity, this); } public void Save(object entity) { this.m_uow.RegisterSave(entity, this); } public void Remove(object entity) { this.m_uow.RegisterRemove(entity, this); } public void ExecuteAdd(object entity) { School school = entity as School; using (IDbCommand cmd = this.m_connection.CreateCommand()) { cmd.CommandType = CommandType.Text; cmd.CommandText = "insert school values(@id, @name)"; cmd.Parameters.Add(new SqlParameter("@id", school.Id)); cmd.Parameters.Add(new SqlParameter("@name", school.Name)); cmd.ExecuteNonQuery(); } } public void ExecuteSave(object entity) { //代码略 } public void ExecuteRemove(object entity) { //代码略 } }
IRepository是数据层的基础接口,从代码中我们看到原先CUD的方法被拆分到了CUD和ExecuteXXX方法中去了,CUD方法负责调用IUnitOfWork的接口,而ExecuteXXX则实现具体的数据库操作
基于NHibernate的IUnitOfWorkRepository实现
先看代码吧
class SchoolRepository : IRepository, IUnitOfWorkRepository { private IUnitOfWork m_uow = null; public SchoolRepository(IDbConnection connection, IUnitOfWork uow) { this.m_uow = uow; } public void Add(object entity) { this.m_uow.RegisterAdd(entity, this); } public void Save(object entity) { this.m_uow.RegisterSave(entity, this); } public void Remove(object entity) { this.m_uow.RegisterRemove(entity, this); } public void ExecuteAdd(object entity) { SessionFactory.CurrentSession.Add(entity); } public void ExecuteSave(object entity) { //代码略 } public void ExecuteRemove(object entity) { //代码略 } }
从基于NHibernate的实现中,我们可以看到ExecuteXXX的方法都是去调用NHibernateSession的相关方法的。
结尾
到此数据层就只差查询了,下次会分享一下关于查询的模式。
文章到这里就结束了,如果有什么问题和错误欢迎留言,谢谢!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· .NET周刊【3月第1期 2025-03-02】
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· [AI/GPT/综述] AI Agent的设计模式综述