关于轻量级开源ORM-Dapper的介绍网上有太多例子,自己无意再重复介绍了,本文只是记录下Dapper在目前项目中的应用或者尝试。先说下背景,来到新公司有段时间了,这期间接触了几个项目,发现有一个问题就是所有这些项目的数据访问层无一例外的都是用最原始的ado.net(SqlHelper类只是对ado.net进行粗糙地封装),而且每次进行CRUD操作时都要传递数据库连接字符串和SqlParamerter数组,还有一些其他的额外参数,而且返回来的结果还得自己再调用另外的方法去反射得到具体的实体对象或实体集合。在现在各种ORM框架大行其道的今天,我实在是受够了目前这种编码的痛苦。于是,萌生了将轻量级的ORM-Dapper引入项目的想法。至于为什么不用EF,我的考虑是EF太过于庞大,而且会颠覆目前项目的开发方式,估计项目组成员接受不了,阻力肯定非常大。这个时候Dapper的好处就是可以无缝地,几乎不用改变现有开发方式就能应用到项目中。于是参考博客园他人博客最大限度地封装了一个DbHelper类,即DataProvider类,并自己先试用,自我认为封装比较彻底,别人用起来也比较顺手。以下是DataProvider类具体代码:
1 using System; 2 using System.Collections.Generic; 3 using System.Configuration; 4 using System.Data; 5 using System.Data.Common; 6 using System.Linq; 7 8 namespace Dapper 9 { 10 /// <summary> 11 /// 数据库访问提供类 12 /// </summary> 13 public class DataProvider 14 { 15 /// <summary> 16 /// 数据库连接字符串 17 /// </summary> 18 private string connectionString = string.Empty; 19 /// <summary> 20 /// 数据库提供程序名称 21 /// </summary> 22 private string providerName = "System.Data.SqlClient"; 23 /// <summary> 24 /// 数据库连接信息缓存 25 /// </summary> 26 private static Dictionary<string, ConnectionInfo> cacheDic = new Dictionary<string, ConnectionInfo>(); 27 28 /// <summary> 29 /// 初始化数据库连接 - 默认为MSSQLSERVER连接 30 /// </summary> 31 public DataProvider() 32 : this("ConnectionString") 33 { } 34 /// <summary> 35 /// 根据指定的连接字符串名称初始化特定的数据库连接 36 /// </summary> 37 /// <param name="connectionString"></param> 38 public DataProvider(string connectionStringName) 39 { 40 try 41 { 42 if (!cacheDic.ContainsKey(connectionStringName)) 43 { 44 var connectSetting = ConfigurationManager.ConnectionStrings[connectionStringName]; 45 if (connectSetting == null) 46 throw new Exception("未设置数据库连接配置!"); 47 this.providerName = connectSetting.ProviderName; 48 this.connectionString = connectSetting.ConnectionString; 49 if (string.IsNullOrEmpty(this.providerName) || string.IsNullOrEmpty(this.connectionString)) 50 throw new Exception("数据库连接配置不正确!"); 51 52 if (!cacheDic.ContainsKey(connectionStringName) && this.TestConnection()) 53 { 54 ConnectionInfo info = new ConnectionInfo(providerName, connectionString); 55 cacheDic.Add(connectionStringName, info); 56 } 57 } 58 else 59 { 60 providerName = cacheDic[connectionStringName].ProviderName; 61 connectionString = cacheDic[connectionStringName].ConnectionString; 62 } 63 } 64 catch (Exception ex) 65 { 66 throw new Exception("初始化数据库连接出错," + ex.Message); 67 } 68 } 69 70 /// <summary> 71 /// 测试数据库连接 72 /// </summary> 73 /// <returns></returns> 74 private bool TestConnection() 75 { 76 bool result = true; 77 try 78 { 79 DbProviderFactory dbFactory = DbProviderFactories.GetFactory(providerName); 80 using (IDbConnection conn = dbFactory.CreateConnection()) 81 { 82 conn.ConnectionString = connectionString; 83 conn.Open(); 84 } 85 } 86 catch (Exception) 87 { 88 result = false; 89 } 90 return result; 91 } 92 /// <summary> 93 /// 创建并打开数据库连接 94 /// </summary> 95 /// <param name="providerName"></param> 96 /// <param name="connectionString"></param> 97 private IDbConnection CreateConnection() 98 { 99 DbProviderFactory dbFactory = DbProviderFactories.GetFactory(providerName); 100 IDbConnection conn = dbFactory.CreateConnection(); 101 conn.ConnectionString = connectionString; 102 conn.Open(); 103 return conn; 104 } 105 106 /// <summary> 107 /// 查询,并返回动态类型集合 108 /// </summary> 109 /// <param name="commondText"></param> 110 /// <param name="param"></param> 111 /// <param name="transaction"></param> 112 /// <param name="buffered"></param> 113 /// <param name="commandTimeout"></param> 114 /// <param name="commandType"></param> 115 /// <returns></returns> 116 public IEnumerable<dynamic> Query(string commondText, object param, IDbTransaction transaction = null, bool buffered = true, int? commandTimeout = null, CommandType? commandType = null) 117 { 118 using (IDbConnection conn = this.CreateConnection()) 119 { 120 return conn.Query(commondText, param, transaction, buffered, commandTimeout, commandType); 121 } 122 } 123 /// <summary> 124 /// 查询,并返回泛型实体对象集合 125 /// </summary> 126 /// <typeparam name="T"></typeparam> 127 /// <param name="commondText"></param> 128 /// <param name="param"></param> 129 /// <param name="transaction"></param> 130 /// <param name="buffered"></param> 131 /// <param name="commandTimeout"></param> 132 /// <param name="commandType"></param> 133 /// <returns></returns> 134 public IList<T> Query<T>(string commondText, object param, IDbTransaction transaction = null, bool buffered = true, int? commandTimeout = null, CommandType? commandType = null) where T : class,new() 135 { 136 using (IDbConnection conn = this.CreateConnection()) 137 { 138 var items = conn.Query<T>(commondText, param, transaction, buffered, commandTimeout, commandType); 139 return items.ToList(); 140 } 141 } 142 /// <summary> 143 /// 查询,并返回单个动态类型对象 144 /// </summary> 145 /// <param name="commondText"></param> 146 /// <param name="param"></param> 147 /// <param name="transaction"></param> 148 /// <param name="buffered"></param> 149 /// <param name="commandTimeout"></param> 150 /// <param name="commandType"></param> 151 /// <returns></returns> 152 public dynamic Single(string commondText, object param, IDbTransaction transaction = null, bool buffered = true, int? commandTimeout = null, CommandType? commandType = null) 153 { 154 using (IDbConnection conn = this.CreateConnection()) 155 { 156 return conn.Query(commondText, param, transaction, buffered, commandTimeout, commandType).FirstOrDefault(); 157 } 158 } 159 /// <summary> 160 /// 查询,并返回单个实体类对象或默认值 161 /// </summary> 162 /// <typeparam name="T"></typeparam> 163 /// <param name="commondText"></param> 164 /// <param name="param"></param> 165 /// <param name="transaction"></param> 166 /// <param name="buffered"></param> 167 /// <param name="commandTimeout"></param> 168 /// <param name="commandType"></param> 169 /// <returns></returns> 170 public T SingleOrDefault<T>(string commondText, object param, IDbTransaction transaction = null, bool buffered = true, int? commandTimeout = null, CommandType? commandType = null) where T : class,new() 171 { 172 using (IDbConnection conn = this.CreateConnection()) 173 { 174 var items = conn.Query<T>(commondText, param, transaction, buffered, commandTimeout, commandType); 175 return items.FirstOrDefault(); 176 } 177 } 178 /// <summary> 179 /// 执行参数化的SQL语句,返回IDataReader 180 /// </summary> 181 /// <param name="commondText"></param> 182 /// <param name="param"></param> 183 /// <param name="transaction"></param> 184 /// <param name="commandTimeout"></param> 185 /// <returns></returns> 186 public IDataReader ExecuteReader(string commondText, object param, IDbTransaction transaction = null, int? commandTimeout = null) 187 { 188 using (IDbConnection conn = this.CreateConnection()) 189 { 190 return conn.ExecuteReader(commondText, param, transaction, commandTimeout); 191 } 192 } 193 /// <summary> 194 /// 执行参数化的SQL语句,并返回单个值(根据泛型类型,指定要返回的值的数据类型) 195 /// </summary> 196 /// <typeparam name="T"></typeparam> 197 /// <param name="commondText"></param> 198 /// <param name="param"></param> 199 /// <param name="transaction"></param> 200 /// <param name="commandTimeout"></param> 201 /// <returns></returns> 202 public T ExecuteScalar<T>(string commondText, object param, IDbTransaction transaction = null, int? commandTimeout = null) 203 { 204 using (IDbConnection conn = this.CreateConnection()) 205 { 206 return (T)conn.ExecuteScalar(commondText, param, transaction, commandTimeout); 207 } 208 } 209 /// <summary> 210 /// 执行参数化的SQL语句,并返回受影响的行数 211 /// </summary> 212 /// <param name="commondText"></param> 213 /// <param name="param"></param> 214 /// <param name="transaction"></param> 215 /// <param name="commandTimeout"></param> 216 /// <returns></returns> 217 public int ExecuteNonQuery(string commondText,object param,IDbTransaction transaction = null,int? commandTimeout = null) 218 { 219 using (IDbConnection conn = this.CreateConnection()) 220 { 221 return conn.Execute(commondText, param, transaction, commandTimeout); 222 } 223 } 224 /// <summary> 225 /// 执行参数化的SQL语句,并返回DataTable 226 /// </summary> 227 /// <param name="commondText"></param> 228 /// <param name="param"></param> 229 /// <param name="transaction"></param> 230 /// <param name="commandTimeout"></param> 231 /// <returns></returns> 232 public DataTable ExecuteDataTable(string commondText, object param, IDbTransaction transaction = null, int? commandTimeout = null) 233 { 234 using (IDbConnection conn = this.CreateConnection()) 235 { 236 DataTable dt = new DataTable(); 237 IDataReader reader = conn.ExecuteReader(commondText, param, transaction, commandTimeout); 238 dt.Load(reader); 239 return dt; 240 } 241 } 242 } 243 /// <summary> 244 /// 数据库连接信息 245 /// </summary> 246 public class ConnectionInfo 247 { 248 private string connectionString = string.Empty; 249 private string providerName = "System.Data.SqlClient"; 250 251 /// <summary> 252 /// 数据库连接字符串 253 /// </summary> 254 public string ConnectionString 255 { 256 get { return connectionString; } 257 } 258 /// <summary> 259 /// 数据库提供程序名称 260 /// </summary> 261 public string ProviderName 262 { 263 get { return providerName; } 264 } 265 266 /// <summary> 267 /// 初始化数据库提供程序名称和连接字符串名称 268 /// </summary> 269 /// <param name="providerName"></param> 270 /// <param name="connectionName"></param> 271 public ConnectionInfo(string providerName, string connectionString) 272 { 273 this.connectionString = connectionString; 274 this.providerName = providerName; 275 } 276 } 277 }
DataProvider.cs
这样写好后,项目中只要引入SqlMapper.cs文件和DataProvider.cs这两个文件,就可以很方便的使用了。
比如以前通过ado.net操作数据库可能是这样的:
1 // 插入一条数据 2 string sqlText = "INSERT INTO T(col1,col2,col3....)VALUES(@col1,@col2,@col3....)"; 3 SqlParameter[] paramArray = new SqlParameter[] { 4 new SqlParameter("col1", value1), 5 new SqlParameter("col2", value2), 6 new SqlParameter("col3", value3) 7 ... 8 }; 9 int count = SqlHelper.ExecuteNonequery(connectionString,sqlText,paramArray); 10 11 // 查询得到实体对象 12 DataSet ds = SqlHelper.QueryDataSet(connectionString, sqlText, paramArray); 13 if(ds != null & ds.Tables.Count > 0) 14 entity = SqlHelper.FillModel<Model>(ds.Tables[0]);
通过ado.net方式操作数据库
相应地,通过DataProvider类操作数据库就变成下面这样了:
1 // 实例化DataProvider对象 2 DataProvider dp = new DataProvider(); 3 // 插入一条数据 4 string sqlText = "INSERT T(col1,col2,col3,...) VALUES(@col1,@col2,@clo3,..) 5 int count = dp.ExecuteNonequery(sqlText, model); 6 // 查询得到实体对象 7 entity = dp.Query<Model>(sqlText, param);
通过DataProvider对象操作数据库
这样,对比之后,是不是感觉代码立马清爽许多,最主要的是原来的编码方式基本不会有什么变化,而且一旦表中字段特别多,或者需要进行批量插入等操作时,就不需要写一大堆参数赋值代码,这时候ORM框架的作用就体现出来了(这里先不谈Dapper的性能),可以说,引入Dapper对项目开发绝对是百利无一害的!
然而,这一切并没有什么卵用,当我满怀希望地向开发经理介绍Dapper时,我担心的事情还是发生了,开发经理虽然肯定了这种做法,但终究还是没同意将Dapper引入项目的建议,当时心里瞬间感觉拔凉拔凉的了!
因此,特以此博客记载一次不成功的尝试,但是对于新技术(或是能够提高生产力的事物)的追求,将不会就此终止!