工作单元(Unit Of Work)模式 ( 二 )
2016-05-31 19:02
417 查看
转自 http://www.cnblogs.com/retop/p/5193394.html
理论介绍
在进行数据库添加、修改、删除时,为了保证事务的一致性,即操作要么全部成功,要么全部失败。例如银行A、B两个账户的转账业务。一方失败都会导致事务的不完整性,从而事务回滚。而工作单元模式可以跟踪事务,在操作完成时对事务进行统一提交。理论参考:http://martinfowler.com/eaaCatalog/unitOfWork.html
具体实践
首先,讲解下设计思想:领域层通过相应的库实现泛型仓储接口来持久化聚合类,之后在抽象库中将对泛型仓储接口提供基础实现,并将对应的实体转化为SQl语句。这样领域层就不需要操作Sql语句即可完成CRUD操作,同时使用工作单元对事务进行统一提交。1)定义仓储接口,包含基本的CRUD操作及其重载不同的查询
1 public interface IRepository<T> 2 { 3 /// <summary> 4 /// 插入对象 5 /// </summary> 6 /// <param name="entity"></param> 7 int Insert(T entity); 8 9 /// <summary> 10 /// 更新对象 11 /// </summary> 12 /// <param name="entity"></param> 13 /// <param name="predicate"></param> 14 int Update(T entity, Expression<Func<T, bool>> express); 15 16 /// <summary> 17 /// 删除对象 18 /// </summary> 19 /// <param name="predicate"></param> 20 int Delete(Expression<Func<T, bool>> express = null); 21 22 /// <summary> 23 /// 查询对象集合 24 /// </summary> 25 /// <param name="predicate"></param> 26 /// <returns></returns> 27 List<T> QueryAll(Expression<Func<T, bool>> express = null); 28 29 /// <summary> 30 /// 查询对象集合 31 /// </summary> 32 /// <param name="index"></param> 33 /// <param name="pagesize"></param> 34 /// <param name="order"></param> 35 /// <param name="asc"></param> 36 /// <param name="express"></param> 37 /// <returns></returns> 38 List<T> QueryAll(int index,int pagesize,List<PropertySortCondition> orderFields, Expression<Func<T, bool>> express = null); 39 40 /// <summary> 41 /// 查询对象集合 42 /// </summary> 43 /// <param name="type"></param> 44 /// <param name="predicate"></param> 45 /// <returns></returns> 46 List<object> QueryAll(Type type, Expression<Func<T, bool>> express = null); 47 48 /// <summary> 49 /// 查询对象 50 /// </summary> 51 /// <param name="predicate"></param> 52 /// <returns></returns> 53 T Query(Expression<Func<T, bool>> express); 54 55 /// <summary> 56 /// 查询数量 57 /// </summary> 58 /// <param name="predicate"></param> 59 /// <returns></returns> 60 object QueryCount(Expression<Func<T, bool>> express = null); 61 }
1 public abstract class UnitOfWorkContext : IUnitOfWorkContext,IDisposable 2 { 3 /// <summary> 4 /// 数据库连接字符串标识 5 /// </summary> 6 public abstract string Key { get; } 7 8 private SqlConnection connection; 9 10 private SqlConnection Connection 11 { 12 get 13 { 14 if (connection == null) 15 { 16 ConnectionStringSettings settings = ConfigurationManager.ConnectionStrings[Key]; 17 connection = new SqlConnection(settings.ConnectionString); 18 } 19 return connection; 20 } 21 } 22 23 /// <summary> 24 /// 注册新对象到事务 25 /// </summary> 26 /// <typeparam name="TEntity"></typeparam> 27 /// <param name="entity"></param> 28 public int ExecuteNonQuery(string commandText, IDictionary<string, object> parameters = null) 29 { 30 Func<SqlCommand, int> excute = (commend) => 31 { 32 return commend.ExecuteNonQuery(); 33 }; 34 return CreateDbCommondAndExcute<int>(commandText, parameters, excute); 35 } 36 37 /// <summary> 38 /// 查询对象集合 39 /// </summary> 40 /// <typeparam name="T"></typeparam> 41 /// <param name="commandText"></param> 42 /// <param name="parameters"></param> 43 /// <param name="load">自定义处理</param> 44 /// <returns>泛型实体集合</returns> 45 46 public List<T> ReadValues<T>(string commandText, IDictionary<string, object> parameters = null, Func<IDataReader, T> load = null) where T : class,new() 47 { 48 Func<SqlCommand, List<T>> excute = (dbCommand) => 49 { 50 List<T> result = new List<T>(); 51 using (IDataReader reader = dbCommand.ExecuteReader()) 52 { 53 while (reader.Read()) 54 { 55 if (load == null) 56 { 57 load = (s) => { return s.GetReaderData<T>(); }; 58 } 59 var item = load(reader); 60 result.Add(item); 61 } 62 return result; 63 } 64 }; 65 return CreateDbCommondAndExcute(commandText, parameters, excute); 66 } 67 68 /// <summary> 69 /// 查询对象集合 70 /// </summary> 71 /// <param name="commandText"></param> 72 /// <param name="parameters"></param> 73 /// <param name="setItem"></param> 74 /// <returns></returns> 75 public List<object> ReadValues(string commandText, Type type, IDictionary<string, object> parameters = null, Action<dynamic> setItem = null) 76 { 77 Func<SqlCommand, List<object>> excute = (dbCommand) => 78 { 79 var result = new List<object>(); 80 81 using (IDataReader dataReader = dbCommand.ExecuteReader()) 82 { 83 while (dataReader.Read()) 84 { 85 var item = dataReader.GetReaderData(type); 86 if (setItem != null) 87 { 88 setItem(item); 89 } 90 result.Add(item); 91 } 92 } 93 return result; 94 }; 95 return CreateDbCommondAndExcute<List<object>>(commandText, parameters, 96 excute); 97 } 98 99 /// <summary> 100 /// 查询对象 101 /// </summary> 102 /// <typeparam name="TEntity"></typeparam> 103 /// <param name="commandText"></param> 104 /// <param name="parameters"></param> 105 /// <param name="excute"></param> 106 /// <returns></returns> 107 public T ExecuteReader<T>(string commandText, IDictionary<string, object> parameters = null, Func<IDataReader, T> load = null) where T : class,new() 108 { 109 Func<SqlCommand, T> excute = (dbCommand) => 110 { 111 var result = default(T); 112 using (IDataReader reader = dbCommand.ExecuteReader()) 113 { 114 while (reader.Read()) 115 { 116 if (load == null) 117 { 118 load = (s) => { return s.GetReaderData<T>(); }; 119 } 120 result = load(reader); 121 } 122 return result; 123 } 124 }; 125 return CreateDbCommondAndExcute<T>(commandText, parameters, excute); 126 } 127 128 /// <summary> 129 /// 查询数量 130 /// </summary> 131 /// <param name="commandText"></param> 132 /// <param name="parameters"></param> 133 /// <returns></returns> 134 public object ExecuteScalar(string commandText, IDictionary<string, object> parameters = null) 135 { 136 Func<SqlCommand, object> excute = (dbCommand) => 137 { 138 return dbCommand.ExecuteScalar(); 139 }; 140 return CreateDbCommondAndExcute(commandText, parameters, excute); 141 } 142 143 /// <summary> 144 /// 创建命令并执行 145 /// </summary> 146 /// <typeparam name="TValue"></typeparam> 147 /// <param name="commandText"></param> 148 /// <param name="parameters"></param> 149 /// <param name="excute"></param> 150 /// <returns></returns> 151 private TValue CreateDbCommondAndExcute<TValue>(string commandText, 152 IDictionary<string, object> parameters, Func<SqlCommand, TValue> excute) 153 { 154 if (Connection.State == ConnectionState.Closed) { Connection.Open(); }; 155 using (SqlCommand command = new SqlCommand()) 156 { 157 command.CommandType = CommandType.Text; 158 command.CommandText = commandText;; 159 command.Connection = Connection; 160 command.SetParameters(parameters); 161 return excute(command); 162 } 163 } 164 165 /// <summary> 166 /// 关闭连接 167 /// </summary> 168 public void Dispose() 169 { 170 if (connection != null) 171 { 172 Connection.Dispose();//非托管资源 173 } 174 } 175 }
在调用方法时需要注意,一个事务涉及多个聚合时,需要保证传递同一工作单元,并在方法的最后调用Commit() 方法。
1 public class Services : IService 2 { 3 private IMemberRespository member; 4 5 private IUnitOfWork unitOfWork; 6 7 public Services(IMemberRespository member, IUnitOfWork unitOfWork) 8 { 9 this.member = member; 10 this.unitOfWork = unitOfWork; 11 } 12 13 /// <summary> 14 /// 测试用例 15 /// </summary> 16 public void Demo() 17 { 18 19 member.Test(); 20 21 unitOfWork.Commit(); 22 } 23 }
后记
该实现中并未实现对多表进行的联合查询,使用Lambda的方式去多表查询,有点自己写一个ORM的性质,由于Lz能力有限,顾有需求的园友可以自行扩展或者使用ORM,若有实现自行扩展的园友,望指教。至此,既实现对数据访问层和领域层解耦,如果园友对我的比较认可,欢迎尝试去使用,在使用中遇到什么问题或有什么好的意见,也希望及时反馈给我。若某些园友不太认可我的设计,也希望批评指出。
源码网盘地址:链接:http://pan.baidu.com/s/1hqXJ3GK 密码:o0he
相关文章推荐
- SELECT INTO 和 INSERT INTO SELECT 两种表复制语句
- oc addChildViewController
- PHP 开发的 API 多版本管理实践
- python基础之socket与socketserver
- 数据库 之 聚合函数
- 文档对象模型理解
- JavaScript:引用类型
- HTML5 之拖放(drag与drop)
- curl_multi_init比curl_init快30倍
- 安卓开发文档学习笔记之实现ActionBar中Tab导航
- 冒泡排序及其优化
- Django管理后台的搭建
- Keep-Alive 总结
- 第13周项目2-动物怎么叫(改)
- Redis系列(1)---Redis的介绍和安装
- jQuery-AJAX
- 仓储(Repository)模式 ( 一 )
- 一线架构师实践指南阅读体会_ADMEMS方法体系理解(转)
- cmd markdown
- 靠谱iOS开发满足的条件