【前言】
作为一款成熟的面向对象高级编程语言,C#在ADO.Net的支持上已然是做的很成熟,我们可以方便地调用ADO.Net操作各类关系型数据库,在使用了多年的Sql_Helper_DG后,由于项目需要,于是乎,就准备写一个Mysql_Helper在实现过程中,发现ADO.Net封装之完善,以及面向对象的封装、继承、多态,有了这些特性,何不把数据库操作封装成为一个通用的类呢,此文由此铺展而来...
【实现功能】
这篇文章将要介绍的主要内容如下:
1、ADO.NET之SqlServer
2、ADO.NET之Oracle
3、ADO.NET之MySql
4、充分利用面向对象的特征,实现通用的操作类
【环境准备】
1、MySql连接器的DLL引用
使用Nuget搜索 MySql.Data 引用即可:
2、Oracle连接器的DLL引用
使用Nuget搜索 Oracle.ManagedDataAccess 进行引用:
【实现思路】
在ADO.NET对SqlServer,Oracle,Mysql的操作熟练的基础上,我们逐渐发现所有的操作都是使用的同一套的东西,不同的是:
SqlServer的操作使用的是SqlConnection、SqlCommand,SqlDataAdapter;
MySql使用的是MySqlConnection、MySqlCommand、MySqlDataAdapter;
Oracle使用的是OracleSqlConnection、OracleCommand、OracleDataAdapter;
该连接类,操作类都分别继承自基础类:DbConnection、DbCommand、DbDataAdapter;
其类间关系如图所示:
1.DbConnection家族
2.DbCommand家族
3.DBDataAdapter家族
了解如上的几个特点后,我们里面能联系到了“多态”这个概念,我们可以使用同一套相同的代码,用“多态”的特性实例化出不同的实例,进而可以进一步封装我们的操作,达到代码精炼可重用的目的。
【实现过程】
1.定义枚举类 Opt_DataBaseType 用于参数选择具体要实例的数据库
1 public enum Opt_DataBaseType 2 { 3 SqlServer, 4 MySql, 5 Oracle 6 }
2.自定义内部类SqlConnection_WR_Safe(多态提供DbConnection的对象、读写分离的支持)
1.在该内部类中,我们定义类属性DbConnection用于承接根据不同的数据库参数多态实例化后的对应Connection
2.实现IDisposable接口,提供释放DbConnection的方法
3.在读数据库连接失败时,及时切换到读写主数据库,提升系统的可用性
1 internal class SqlConnection_WR_Safe : IDisposable 2 { 3 ///4 /// SqlConnection 5 /// 6 public DbConnection DbConnection { get; set; } 7 8 public SqlConnection_WR_Safe(Opt_DataBaseType dataBaseType, string ConnString_RW) 9 { 10 this.DbConnection = GetDbConnection(dataBaseType, ConnString_RW); 11 } 12 /** 13 * if read db disabled,switchover to read write db immediately 14 * */ 15 public SqlConnection_WR_Safe(Opt_DataBaseType dataBaseType, string ConnString_R, string ConnString_RW) 16 { 17 try 18 { 19 this.DbConnection = GetDbConnection(dataBaseType, ConnString_R); 20 } 21 catch (Exception) 22 { 23 this.DbConnection = GetDbConnection(dataBaseType, ConnString_RW); 24 } 25 } 26 27 /// 28 /// GetDataBase ConnectionString by database type and connection string -- private use 29 /// 30 /// 31 /// 32 /// 33 private DbConnection GetDbConnection(Opt_DataBaseType dataBaseType, string ConnString) 34 { 35 switch (dataBaseType) 36 { 37 case Opt_DataBaseType.SqlServer: 38 return new SqlConnection(ConnString); 39 case Opt_DataBaseType.MySql: 40 return new MySqlConnection(ConnString); 41 case Opt_DataBaseType.Oracle: 42 return new OracleConnection(ConnString); 43 default: 44 return new SqlConnection(ConnString); 45 } 46 } 47 /// 48 /// Must Close Connection after use 49 /// 50 public void Dispose() 51 { 52 if (this.DbConnection != null) 53 { 54 this.DbConnection.Dispose(); 55 } 56 } 57 }
3.自定义内部类 DbCommandCommon 用于提供DbCommand对象
1 internal class DbCommandCommon : IDisposable 2 { 3 ///4 /// common dbcommand 5 /// 6 public DbCommand DbCommand { get; set; } 7 public DbCommandCommon(Opt_DataBaseType dataBaseType) 8 { 9 this.DbCommand = GetDbCommand(dataBaseType); 10 } 11 12 /// 13 /// Get DbCommand select database type 14 /// 15 /// 16 /// 17 private DbCommand GetDbCommand(Opt_DataBaseType dataBaseType) 18 { 19 switch (dataBaseType) 20 { 21 case Opt_DataBaseType.SqlServer: 22 return new SqlCommand(); 23 case Opt_DataBaseType.MySql: 24 return new MySqlCommand(); 25 case Opt_DataBaseType.Oracle: 26 return new OracleCommand(); 27 default: 28 return new SqlCommand(); 29 } 30 } 31 /// 32 /// must dispose after use 33 /// 34 public void Dispose() 35 { 36 if (this.DbCommand != null) 37 { 38 this.DbCommand.Dispose(); 39 } 40 } 41 }
4.自定义内部类 DbDataAdapterCommon 用于提供DbDataAdapter
该类继承自DbDataAdapter,以实现DataAdapter的Fill方法,可以将结果集填充到DataSet中去。
1 ///2 /// DbDataAdapterCommon 3 /// 4 internal class DbDataAdapterCommon : DbDataAdapter, IDisposable 5 { 6 public DbDataAdapter DbDataAdapter { get; set; } 7 public DbDataAdapterCommon(Opt_DataBaseType dataBaseType, DbCommand dbCommand) 8 { 9 //get dbAdapter 10 this.DbDataAdapter = GetDbAdapter(dataBaseType, dbCommand); 11 //provid select command 12 this.SelectCommand = dbCommand; 13 } 14 private DbDataAdapter GetDbAdapter(Opt_DataBaseType dataBaseType, DbCommand dbCommand) 15 { 16 switch (dataBaseType) 17 { 18 case Opt_DataBaseType.SqlServer: 19 return new SqlDataAdapter(); 20 case Opt_DataBaseType.MySql: 21 return new MySqlDataAdapter(); 22 case Opt_DataBaseType.Oracle: 23 return new OracleDataAdapter(); 24 default: 25 return new SqlDataAdapter(); 26 } 27 } 28 /// 29 /// must dispose after use 30 /// 31 public new void Dispose() 32 { 33 if (this.DbDataAdapter != null) 34 { 35 this.DbDataAdapter.Dispose(); 36 } 37 } 38 }
5.在执行Sql查询的时候,我们便使用我们自定义的内部类进行操作
>1 这里以ExecuteNonQuery为例:
1 public static int ExecuteNonQuery(string commandTextOrSpName, CommandType commandType = CommandType.Text) 2 { 3 using (SqlConnection_WR_Safe conn = new SqlConnection_WR_Safe(dataBaseType, ConnString_RW)) 4 { 5 using (DbCommandCommon cmd = new DbCommandCommon(dataBaseType)) 6 { 7 PreparCommand(conn.DbConnection, cmd.DbCommand, commandTextOrSpName, commandType); 8 return cmd.DbCommand.ExecuteNonQuery(); 9 } 10 } 11 }
该代码通过参数DataBaseType确定要实例化的数据库类型,ConnString_RW传入写数据库的连接字符串进行实例化,DbCommand也是使用dataBaseType实例我们需要实际操作的数据库对象。
>2 查询ExecuteDataSet方法:
该方法通过参数dataBaseType确定要实例化的具体DbConnection,通过读写分离的连接字符串进行选择读库和写库。
1 public static DataSet ExecuteDataSet(string commandTextOrSpName, CommandType commandType = CommandType.Text) 2 { 3 using (SqlConnection_WR_Safe conn = new SqlConnection_WR_Safe(dataBaseType, ConnString_R, ConnString_RW)) 4 { 5 using (DbCommandCommon cmd = new DbCommandCommon(dataBaseType)) 6 { 7 PreparCommand(conn.DbConnection, cmd.DbCommand, commandTextOrSpName, commandType); 8 using (DbDataAdapterCommon da = new DbDataAdapterCommon(dataBaseType, cmd.DbCommand)) 9 { 10 DataSet ds = new DataSet(); 11 da.Fill(ds); 12 return ds; 13 } 14 } 15 } 16 }
全部代码见此:
1、数据库选择器枚举类:Opt_DataBaseType->
1 /********************************************************* 2 * CopyRight: QIXIAO CODE BUILDER. 3 * Version:4.2.0 4 * Author:qixiao(柒小) 5 * Create:2017-09-26 17:54:28 6 * Update:2017-09-26 17:54:28 7 * E-mail: [email protected] | [email protected] 8 * GitHub: https://github.com/dong666 9 * Personal web site: http://qixiao.me 10 * Technical WebSit: http://www.cnblogs.com/qixiaoyizhan/ 11 * Description: 12 * Thx , Best Regards ~ 13 *********************************************************/ 14 namespace QX_Frame.Bantina.Options 15 { 16 public enum Opt_DataBaseType 17 { 18 SqlServer, 19 MySql, 20 Oracle 21 } 22 }
2、主类代码Db_Helper_DG->
1 /********************************************************* 2 * CopyRight: QIXIAO CODE BUILDER. 3 * Version:4.2.0 4 * Author:qixiao(柒小) 5 * Create:2017-9-26 17:41:42 6 * Update:2017-9-26 17:41:42 7 * E-mail: [email protected] | [email protected] 8 * GitHub: https://github.com/dong666 9 * Personal web site: http://qixiao.me 10 * Technical WebSit: http://www.cnblogs.com/qixiaoyizhan/ 11 * Description: 12 * Thx , Best Regards ~ 13 *********************************************************/ 14 using MySql.Data.MySqlClient; 15 using Oracle.ManagedDataAccess.Client; 16 using QX_Frame.Bantina.Options; 17 using System; 18 using System.Collections.Generic; 19 using System.ComponentModel; 20 using System.Data; 21 using System.Data.Common; 22 using System.Data.SqlClient; 23 using System.Linq; 24 using System.Reflection; 25 26 namespace QX_Frame.Bantina 27 { 28 public abstract class Db_Helper_DG 29 { 30 #region ConnString 链接字符串声明 31 32 ///33 /// 连接字符串 ConnString_Default 默认,且赋值时会直接覆盖掉读写 34 /// 35 private static string _connString = Configs.QX_Frame_Helper_DG_Config.ConnectionString_DB_QX_Frame_Default; 36 public static string ConnString_Default 37 { 38 get { return _connString; } 39 set 40 { 41 _connString = value; 42 ConnString_RW = _connString; 43 ConnString_R = _connString; 44 } 45 } 46 /// 47 /// 连接字符串 ConnString_RW 读写数据库使用 48 /// 49 public static string ConnString_RW = _connString; 50 /// 51 /// 连接字符串 ConnString_R 读数据库使用 52 /// 53 public static string ConnString_R = _connString; 54 /// 55 /// DataBaseType Select default:sqlserver 56 /// 57 public static Opt_DataBaseType dataBaseType = Configs.QX_Frame_Helper_DG_Config.DataBaseType; 58 59 #endregion 60 61 static Db_Helper_DG() 62 { 63 //if (string.IsNullOrEmpty(ConnString_RW) || string.IsNullOrEmpty(ConnString_R)) 64 //{ 65 // throw new ArgumentNullException("ConnString Can Not Be Null !"); 66 //} 67 } 68 69 #region ExcuteNonQuery 执行sql语句或者存储过程,返回影响的行数---ExcuteNonQuery 70 /// 71 /// 执行sql语句或存储过程,返回受影响的行数,不带参数。 72 /// 73 /// 连接字符串,可以自定义,可以以使用SqlHelper_DG.ConnString 74 /// sql语句或存储过程名称 75 /// 命令类型 有默认值CommandType.Text 76 /// 返回受影响的行数 77 public static int ExecuteNonQuery(string commandTextOrSpName, CommandType commandType = CommandType.Text) 78 { 79 using (SqlConnection_WR_Safe conn = new SqlConnection_WR_Safe(dataBaseType, ConnString_RW)) 80 { 81 using (DbCommandCommon cmd = new DbCommandCommon(dataBaseType)) 82 { 83 PreparCommand(conn.DbConnection, cmd.DbCommand, commandTextOrSpName, commandType); 84 return cmd.DbCommand.ExecuteNonQuery(); 85 } 86 } 87 } 88 /// 89 /// 执行sql语句或存储过程,返回受影响的行数。 90 /// 91 /// 连接字符串,可以自定义,可以以使用SqlHelper_DG.ConnString 92 /// sql语句或存储过程名称 93 /// 命令类型 t 94 /// SqlParameter[]参数数组,允许空 95 /// 返回受影响的行数 96 public static int ExecuteNonQuery(string commandTextOrSpName, CommandType commandType, params DbParameter[] parms) 97 { 98 using (SqlConnection_WR_Safe conn = new SqlConnection_WR_Safe(dataBaseType, ConnString_RW)) 99 { 100 using (DbCommandCommon cmd = new DbCommandCommon(dataBaseType)) 101 { 102 PreparCommand(conn.DbConnection, cmd.DbCommand, commandTextOrSpName, commandType, parms);//参数增加了commandType 可以自己编辑执行方式 103 return cmd.DbCommand.ExecuteNonQuery(); 104 } 105 } 106 } 107 /// 108 /// 执行sql命令,返回受影响的行数。 109 /// 110 /// 连接字符串,可以自定义,可以以使用SqlHelper_DG.ConnString 111 /// sql语句或存储过程名称 112 /// 命令类型 113 /// object[]参数数组,允许空 114 /// 返回受影响的行数 115 public static int ExecuteNonQuery(string commandTextOrSpName, CommandType commandType, params object[] obj) 116 { 117 using (SqlConnection_WR_Safe conn = new SqlConnection_WR_Safe(dataBaseType, ConnString_RW)) 118 { 119 using (DbCommandCommon cmd = new DbCommandCommon(dataBaseType)) 120 { 121 PreparCommand(conn.DbConnection, cmd.DbCommand, commandTextOrSpName, commandType, obj);//参数增加了commandType 可以自己编辑执行方式 122 return cmd.DbCommand.ExecuteNonQuery(); 123 } 124 } 125 } 126 #endregion 127 128 #region ExecuteScalar 执行sql语句或者存储过程,执行单条语句,返回单个结果---ScalarExecuteScalar 129 /// 130 /// 执行sql语句或存储过程 返回ExecuteScalar (返回自增的ID)不带参数 131 /// 132 /// 连接字符串,可以自定义,可以以使用SqlHelper_DG.ConnString 133 /// sql语句或存储过程名称 134 /// 命令类型 有默认值CommandType.Text 135 /// 136 public static object ExecuteScalar(string commandTextOrSpName, CommandType commandType = CommandType.Text) 137 { 138 using (SqlConnection_WR_Safe conn = new SqlConnection_WR_Safe(dataBaseType, ConnString_R, ConnString_RW)) 139 { 140 using (DbCommandCommon cmd = new DbCommandCommon(dataBaseType)) 141 { 142 PreparCommand(conn.DbConnection, cmd.DbCommand, commandTextOrSpName, commandType); 143 return cmd.DbCommand.ExecuteScalar(); 144 } 145 } 146 } 147 /// 148 /// 执行sql语句或存储过程 返回ExecuteScalar (返回自增的ID) 149 /// 150 /// 连接字符串,可以自定义,可以以使用SqlHelper_DG.ConnString 151 /// sql语句或存储过程名称 152 /// 命令类型 153 /// SqlParameter[]参数数组,允许空 154 /// 155 public static object ExecuteScalar(string commandTextOrSpName, CommandType commandType, params DbParameter[] parms) 156 { 157 using (SqlConnection_WR_Safe conn = new SqlConnection_WR_Safe(dataBaseType, ConnString_R, ConnString_RW)) 158 { 159 using (DbCommandCommon cmd = new DbCommandCommon(dataBaseType)) 160 { 161 PreparCommand(conn.DbConnection, cmd.DbCommand, commandTextOrSpName, commandType, parms); 162 return cmd.DbCommand.ExecuteScalar(); 163 } 164 165 } 166 } 167 /// 168 /// 执行sql语句或存储过程 返回ExecuteScalar (返回自增的ID) 169 /// 170 /// 连接字符串,可以自定义,可以以使用SqlHelper_DG.ConnString 171 /// sql语句或存储过程名称 172 /// 命令类型 173 /// object[]参数数组,允许空 174 /// 175 public static object ExecuteScalar(string commandTextOrSpName, CommandType commandType, params object[] obj) 176 { 177 using (SqlConnection_WR_Safe conn = new SqlConnection_WR_Safe(dataBaseType, ConnString_R, ConnString_RW)) 178 { 179 using (DbCommandCommon cmd = new DbCommandCommon(dataBaseType)) 180 { 181 PreparCommand(conn.DbConnection, cmd.DbCommand, commandTextOrSpName, commandType, obj); 182 return cmd.DbCommand.ExecuteScalar(); 183 } 184 } 185 } 186 #endregion 187 188 #region ExecuteScalar 执行sql语句或者存储过程,返回DataReader---DaataReader 189 /// 190 /// 执行sql语句或存储过程 返回DataReader 不带参数 191 /// 192 /// 连接字符串,可以自定义,可以以使用SqlHelper_DG.ConnString 193 /// sql语句或存储过程名称 194 /// 命令类型 有默认值CommandType.Text 195 /// 196 public static DbDataReader ExecuteReader(string commandTextOrSpName, CommandType commandType = CommandType.Text) 197 { 198 //sqlDataReader不能用using 会关闭conn 导致不能获取到返回值。注意:DataReader获取值时必须保持连接状态 199 SqlConnection_WR_Safe conn = new SqlConnection_WR_Safe(dataBaseType, ConnString_R, ConnString_RW); 200 DbCommandCommon cmd = new DbCommandCommon(dataBaseType); 201 PreparCommand(conn.DbConnection, cmd.DbCommand, commandTextOrSpName, commandType); 202 return cmd.DbCommand.ExecuteReader(CommandBehavior.CloseConnection); 203 } 204 /// 205 /// 执行sql语句或存储过程 返回DataReader 206 /// 207 /// 连接字符串,可以自定义,可以以使用SqlHelper_DG.ConnString 208 /// sql语句或存储过程名称 209 /// 命令类型 210 /// SqlParameter[]参数数组,允许空 211 /// 212 public static DbDataReader ExecuteReader(string commandTextOrSpName, CommandType commandType, params DbParameter[] parms) 213 { 214 //sqlDataReader不能用using 会关闭conn 导致不能获取到返回值。注意:DataReader获取值时必须保持连接状态 215 SqlConnection_WR_Safe conn = new SqlConnection_WR_Safe(dataBaseType, ConnString_R, ConnString_RW); 216 DbCommandCommon cmd = new DbCommandCommon(dataBaseType); 217 PreparCommand(conn.DbConnection, cmd.DbCommand, commandTextOrSpName, commandType, parms); 218 return cmd.DbCommand.ExecuteReader(CommandBehavior.CloseConnection); 219 } 220 /// 221 /// 执行sql语句或存储过程 返回DataReader 222 /// 223 /// 连接字符串,可以自定义,可以以使用SqlHelper_DG.ConnString 224 /// sql语句或存储过程名称 225 /// 命令类型 226 /// object[]参数数组,允许空 227 /// 228 public static DbDataReader ExecuteReader(string commandTextOrSpName, CommandType commandType, params object[] obj) 229 { 230 //sqlDataReader不能用using 会关闭conn 导致不能获取到返回值。注意:DataReader获取值时必须保持连接状态 231 SqlConnection_WR_Safe conn = new SqlConnection_WR_Safe(dataBaseType, ConnString_R, ConnString_RW); 232 DbCommandCommon cmd = new DbCommandCommon(dataBaseType); 233 PreparCommand(conn.DbConnection, cmd.DbCommand, commandTextOrSpName, commandType, obj); 234 return cmd.DbCommand.ExecuteReader(CommandBehavior.CloseConnection); 235 } 236 #endregion 237 238 #region ExecuteDataTable 执行sql语句或者存储过程,返回一个DataTable---DataTable 239 240 /** 241 * Update At 2017-3-2 14:58:45 242 * Add the ExecuteDataTable Method into Sql_Helper_DG 243 **/ 244 245 /// 246 /// 执行sql语句或存储过程,返回DataTable不带参数 247 /// 248 /// 连接字符串,可以自定义,可以以使用SqlHelper_DG.ConnString 249 /// sql语句或存储过程名称 250 /// 命令类型 有默认值CommandType.Text 251 /// 252 public static DataTable ExecuteDataTable(string commandTextOrSpName, CommandType commandType = CommandType.Text) 253 { 254 using (SqlConnection_WR_Safe conn = new SqlConnection_WR_Safe(dataBaseType, ConnString_R, ConnString_RW)) 255 { 256 using (DbCommandCommon cmd = new DbCommandCommon(dataBaseType)) 257 { 258 PreparCommand(conn.DbConnection, cmd.DbCommand, commandTextOrSpName, commandType); 259 using (DbDataAdapterCommon da = new DbDataAdapterCommon(dataBaseType, cmd.DbCommand)) 260 { 261 DataSet ds = new DataSet(); 262 da.Fill(ds); 263 if (ds.Tables.Count > 0) 264 { 265 return ds.Tables[0]; 266 } 267 return default(DataTable); 268 } 269 } 270 } 271 } 272 /// 273 /// 执行sql语句或存储过程,返回DataTable 274 /// 275 /// 连接字符串,可以自定义,可以以使用SqlHelper_DG.ConnString 276 /// sql语句或存储过程名称 277 /// 命令类型 278 /// SqlParameter[]参数数组,允许空 279 /// 280 public static DataTable ExecuteDataTable(string commandTextOrSpName, CommandType commandType, params DbParameter[] parms) 281 { 282 using (SqlConnection_WR_Safe conn = new SqlConnection_WR_Safe(dataBaseType, ConnString_R, ConnString_RW)) 283 { 284 using (DbCommandCommon cmd = new DbCommandCommon(dataBaseType)) 285 { 286 PreparCommand(conn.DbConnection, cmd.DbCommand, commandTextOrSpName, commandType, parms); 287 using (DbDataAdapterCommon da = new DbDataAdapterCommon(dataBaseType, cmd.DbCommand)) 288 { 289 DataSet ds = new DataSet(); 290 da.Fill(ds); 291 if (ds.Tables.Count > 0) 292 { 293 return ds.Tables[0]; 294 } 295 return default(DataTable); 296 } 297 } 298 } 299 } 300 /// 301 /// 执行sql语句或存储过程,返回DataTable 302 /// 303 /// 连接字符串,可以自定义,可以以使用SqlHelper_DG.ConnString 304 /// sql语句或存储过程名称 305 /// 命令类型 306 /// object[]参数数组,允许空 307 /// 308 public static DataTable ExecuteDataTable(string commandTextOrSpName, CommandType commandType, params object[] obj) 309 { 310 using (SqlConnection_WR_Safe conn = new SqlConnection_WR_Safe(dataBaseType, ConnString_R, ConnString_RW)) 311 { 312 using (DbCommandCommon cmd = new DbCommandCommon(dataBaseType)) 313 { 314 PreparCommand(conn.DbConnection, cmd.DbCommand, commandTextOrSpName, commandType, obj); 315 using (DbDataAdapterCommon da = new DbDataAdapterCommon(dataBaseType, cmd.DbCommand)) 316 { 317 DataSet ds = new DataSet(); 318 da.Fill(ds); 319 if (ds.Tables.Count > 0) 320 { 321 return ds.Tables[0]; 322 } 323 return default(DataTable); 324 } 325 } 326 } 327 } 328 #endregion 329 330 #region ExecuteDataSet 执行sql语句或者存储过程,返回一个DataSet---DataSet 331 /// 332 /// 执行sql语句或存储过程,返回DataSet 不带参数 333 /// 334 /// 连接字符串,可以自定义,可以以使用SqlHelper_DG.ConnString 335 /// sql语句或存储过程名称 336 /// 命令类型 有默认值CommandType.Text 337 /// 338 public static DataSet ExecuteDataSet(string commandTextOrSpName, CommandType commandType = CommandType.Text) 339 { 340 using (SqlConnection_WR_Safe conn = new SqlConnection_WR_Safe(dataBaseType, ConnString_R, ConnString_RW)) 341 { 342 using (DbCommandCommon cmd = new DbCommandCommon(dataBaseType)) 343 { 344 PreparCommand(conn.DbConnection, cmd.DbCommand, commandTextOrSpName, commandType); 345 using (DbDataAdapterCommon da = new DbDataAdapterCommon(dataBaseType, cmd.DbCommand)) 346 { 347 DataSet ds = new DataSet(); 348 da.Fill(ds); 349 return ds; 350 } 351 } 352 } 353 } 354 /// 355 /// 执行sql语句或存储过程,返回DataSet 356 /// 357 /// 连接字符串,可以自定义,可以以使用SqlHelper_DG.ConnString 358 /// sql语句或存储过程名称 359 /// 命令类型 360 /// SqlParameter[]参数数组,允许空 361 /// 362 public static DataSet ExecuteDataSet(string commandTextOrSpName, CommandType commandType, params DbParameter[] parms) 363 { 364 using (SqlConnection_WR_Safe conn = new SqlConnection_WR_Safe(dataBaseType, ConnString_R, ConnString_RW)) 365 { 366 using (DbCommandCommon cmd = new DbCommandCommon(dataBaseType)) 367 { 368 PreparCommand(conn.DbConnection, cmd.DbCommand, commandTextOrSpName, commandType, parms); 369 using (DbDataAdapterCommon da = new DbDataAdapterCommon(dataBaseType, cmd.DbCommand)) 370 { 371 DataSet ds = new DataSet(); 372 da.Fill(ds); 373 return ds; 374 } 375 } 376 } 377 } 378 /// 379 /// 执行sql语句或存储过程,返回DataSet 380 /// 381 /// 连接字符串,可以自定义,可以以使用SqlHelper_DG.ConnString 382 /// sql语句或存储过程名称 383 /// 命令类型 384 /// object[]参数数组,允许空 385 /// 386 public static DataSet ExecuteDataSet(string commandTextOrSpName, CommandType commandType, params object[] obj) 387 { 388 using (SqlConnection_WR_Safe conn = new SqlConnection_WR_Safe(dataBaseType, ConnString_R, ConnString_RW)) 389 { 390 using (DbCommandCommon cmd = new DbCommandCommon(dataBaseType)) 391 { 392 PreparCommand(conn.DbConnection, cmd.DbCommand, commandTextOrSpName, commandType, obj); 393 using (DbDataAdapterCommon da = new DbDataAdapterCommon(dataBaseType, cmd.DbCommand)) 394 { 395 DataSet ds = new DataSet(); 396 da.Fill(ds); 397 return ds; 398 } 399 } 400 } 401 } 402 #endregion 403 404 #region ExecuteList Entity 执行sql语句或者存储过程,返回一个List ---List 405 public static List ExecuteList (string commandTextOrSpName, CommandType commandType = CommandType.Text) where Entity : class 406 { 407 return GetListFromDataSet (ExecuteDataSet(commandTextOrSpName, commandType)); 408 } 409 public static List ExecuteList (string commandTextOrSpName, CommandType commandType, params DbParameter[] parms) where Entity : class 410 { 411 return GetListFromDataSet (ExecuteDataSet(commandTextOrSpName, commandType, parms)); 412 } 413 public static List ExecuteList (string commandTextOrSpName, CommandType commandType, params object[] obj) where Entity : class 414 { 415 return GetListFromDataSet (ExecuteDataSet(commandTextOrSpName, commandType, obj)); 416 } 417 #endregion 418 419 #region ExecuteEntity 执行sql语句或者存储过程,返回一个Entity---Entity 420 public static Entity ExecuteEntity (string commandTextOrSpName, CommandType commandType = CommandType.Text) where Entity : class 421 { 422 return GetEntityFromDataSet (ExecuteDataSet(commandTextOrSpName, commandType)); 423 } 424 public static Entity ExecuteEntity (string commandTextOrSpName, CommandType commandType, params DbParameter[] parms) where Entity : class 425 { 426 return GetEntityFromDataSet (ExecuteDataSet(commandTextOrSpName, commandType, parms)); 427 } 428 public static Entity ExecuteEntity (string commandTextOrSpName, CommandType commandType, params object[] obj) where Entity : class 429 { 430 return GetEntityFromDataSet (ExecuteDataSet(commandTextOrSpName, commandType, obj)); 431 } 432 #endregion 433 434 #region ---PreparCommand 构建一个通用的command对象供内部方法进行调用--- 435 /// 436 /// 不带参数的设置sqlcommand对象 437 /// 438 /// sqlconnection对象 439 /// sqlcommmand对象 440 /// sql语句或存储过程名称 441 /// 语句的类型 442 private static void PreparCommand(DbConnection conn, DbCommand cmd, string commandTextOrSpName, CommandType commandType) 443 { 444 //打开连接 445 if (conn.State != ConnectionState.Open) 446 { 447 conn.Open(); 448 } 449 450 //设置SqlCommand对象的属性值 451 cmd.Connection = conn; 452 cmd.CommandType = commandType; 453 cmd.CommandText = commandTextOrSpName; 454 cmd.CommandTimeout = 60; 455 } 456 /// 457 /// 设置一个等待执行的SqlCommand对象 458 /// 459 /// sqlconnection对象 460 /// sqlcommmand对象 461 /// sql语句或存储过程名称 462 /// 语句的类型 463 /// 参数,sqlparameter类型,需要指出所有的参数名称 464 private static void PreparCommand(DbConnection conn, DbCommand cmd, string commandTextOrSpName, CommandType commandType, params SqlParameter[] parms) 465 { 466 //打开连接 467 if (conn.State != ConnectionState.Open) 468 { 469 conn.Open(); 470 } 471 472 //设置SqlCommand对象的属性值 473 cmd.Connection = conn; 474 cmd.CommandType = commandType; 475 cmd.CommandText = commandTextOrSpName; 476 cmd.CommandTimeout = 60; 477 478 if (parms != null) 479 { 480 cmd.Parameters.Clear(); 481 cmd.Parameters.AddRange(parms); 482 } 483 } 484 /// 485 /// PreparCommand方法,可变参数为object需要严格按照参数顺序传参 486 /// 之所以会用object参数方法是为了我们能更方便的调用存储过程,不必去关系存储过程参数名是什么,知道它的参数顺序就可以了 sqlparameter必须指定每一个参数名称 487 /// 488 /// sqlconnection对象 489 /// sqlcommmand对象 490 /// sql语句或存储过程名称 491 /// 语句的类型 492 /// 参数,object类型,需要按顺序赋值 493 private static void PreparCommand(DbConnection conn, DbCommand cmd, string commandTextOrSpName, CommandType commandType, params object[] parms) 494 { 495 //打开连接 496 if (conn.State != ConnectionState.Open) 497 { 498 conn.Open(); 499 } 500 501 //设置SqlCommand对象的属性值 502 cmd.Connection = conn; 503 cmd.CommandType = commandType; 504 cmd.CommandText = commandTextOrSpName; 505 cmd.CommandTimeout = 60; 506 507 cmd.Parameters.Clear(); 508 if (parms != null) 509 { 510 cmd.Parameters.AddRange(parms); 511 } 512 } 513 #endregion 514 515 #region 通过Model反射返回结果集 Model为 Entity 泛型变量的真实类型---反射返回结果集 516 /// 517 /// 反射返回一个List T 类型的结果集 518 /// 519 /// Model中对象类型 520 /// DataSet结果集 521 /// 522 public static List GetListFromDataSet (DataSet ds) where Entity : class 523 { 524 List list = new List ();//实例化一个list对象 525 PropertyInfo[] propertyInfos = typeof(Entity).GetProperties(); //获取T对象的所有公共属性 526 527 DataTable dt = ds.Tables[0]; // 获取到ds的dt 528 if (dt.Rows.Count > 0) 529 { 530 //判断读取的行是否>0 即数据库数据已被读取 531 foreach (DataRow row in dt.Rows) 532 { 533 Entity model1 = System.Activator.CreateInstance ();//实例化一个对象,便于往list里填充数据 534 foreach (PropertyInfo propertyInfo in propertyInfos) 535 { 536 try 537 { 538 //遍历模型里所有的字段 539 if (row[propertyInfo.Name] != System.DBNull.Value) 540 { 541 //判断值是否为空,如果空赋值为null见else 542 if (propertyInfo.PropertyType.IsGenericType && propertyInfo.PropertyType.GetGenericTypeDefinition().Equals(typeof(Nullable<>))) 543 { 544 //如果convertsionType为nullable类,声明一个NullableConverter类,该类提供从Nullable类到基础基元类型的转换 545 NullableConverter nullableConverter = new NullableConverter(propertyInfo.PropertyType); 546 //将convertsionType转换为nullable对的基础基元类型 547 propertyInfo.SetValue(model1, Convert.ChangeType(row[propertyInfo.Name], nullableConverter.UnderlyingType), null); 548 } 549 else 550 { 551 propertyInfo.SetValue(model1, Convert.ChangeType(row[propertyInfo.Name], propertyInfo.PropertyType), null); 552 } 553 } 554 else 555 { 556 propertyInfo.SetValue(model1, null, null);//如果数据库的值为空,则赋值为null 557 } 558 } 559 catch (Exception) 560 { 561 propertyInfo.SetValue(model1, null, null);//如果数据库的值为空,则赋值为null 562 } 563 } 564 list.Add(model1);//将对象填充到list中 565 } 566 } 567 return list; 568 } 569 /// 570 /// 反射返回一个T类型的结果 571 /// 572 /// Model中对象类型 573 /// SqlDataReader结果集 574 /// 575 public static Entity GetEntityFromDataReader (DbDataReader reader) where Entity : class 576 { 577 Entity model = System.Activator.CreateInstance (); //实例化一个T类型对象 578 PropertyInfo[] propertyInfos = model.GetType().GetProperties(); //获取T对象的所有公共属性 579 using (reader) 580 { 581 if (reader.Read()) 582 { 583 foreach (PropertyInfo propertyInfo in propertyInfos) 584 { 585 //遍历模型里所有的字段 586 if (reader[propertyInfo.Name] != System.DBNull.Value) 587 { 588 //判断值是否为空,如果空赋值为null见else 589 if (propertyInfo.PropertyType.IsGenericType && propertyInfo.PropertyType.GetGenericTypeDefinition().Equals(typeof(Nullable<>))) 590 { 591 //如果convertsionType为nullable类,声明一个NullableConverter类,该类提供从Nullable类到基础基元类型的转换 592 NullableConverter nullableConverter = new NullableConverter(propertyInfo.PropertyType); 593 //将convertsionType转换为nullable对的基础基元类型 594 propertyInfo.SetValue(model, Convert.ChangeType(reader[propertyInfo.Name], nullableConverter.UnderlyingType), null); 595 } 596 else 597 { 598 propertyInfo.SetValue(model, Convert.ChangeType(reader[propertyInfo.Name], propertyInfo.PropertyType), null); 599 } 600 } 601 else 602 { 603 propertyInfo.SetValue(model, null, null);//如果数据库的值为空,则赋值为null 604 } 605 } 606 return model;//返回T类型的赋值后的对象 model 607 } 608 } 609 return default(Entity);//返回引用类型和值类型的默认值0或null 610 } 611 /// 612 /// 反射返回一个T类型的结果 613 /// 614 /// Model中对象类型 615 /// DataSet结果集 616 /// 617 public static Entity GetEntityFromDataSet (DataSet ds) where Entity : class 618 { 619 return GetListFromDataSet (ds).FirstOrDefault(); 620 } 621 #endregion 622 } 623 /** 624 * author:qixiao 625 * time:2017-9-18 18:02:23 626 * description:safe create sqlconnection support 627 * */ 628 internal class SqlConnection_WR_Safe : IDisposable 629 { 630 /// 631 /// SqlConnection 632 /// 633 public DbConnection DbConnection { get; set; } 634 635 public SqlConnection_WR_Safe(Opt_DataBaseType dataBaseType, string ConnString_RW) 636 { 637 this.DbConnection = GetDbConnection(dataBaseType, ConnString_RW); 638 } 639 /** 640 * if read db disabled,switchover to read write db immediately 641 * */ 642 public SqlConnection_WR_Safe(Opt_DataBaseType dataBaseType, string ConnString_R, string ConnString_RW) 643 { 644 try 645 { 646 this.DbConnection = GetDbConnection(dataBaseType, ConnString_R); 647 } 648 catch (Exception) 649 { 650 this.DbConnection = GetDbConnection(dataBaseType, ConnString_RW); 651 } 652 } 653 654 /// 655 /// GetDataBase ConnectionString by database type and connection string -- private use 656 /// 657 /// 658 /// 659 /// 660 private DbConnection GetDbConnection(Opt_DataBaseType dataBaseType, string ConnString) 661 { 662 switch (dataBaseType) 663 { 664 case Opt_DataBaseType.SqlServer: 665 return new SqlConnection(ConnString); 666 case Opt_DataBaseType.MySql: 667 return new MySqlConnection(ConnString); 668 case Opt_DataBaseType.Oracle: 669 return new OracleConnection(ConnString); 670 default: 671 return new SqlConnection(ConnString); 672 } 673 } 674 /// 675 /// Must Close Connection after use 676 /// 677 public void Dispose() 678 { 679 if (this.DbConnection != null) 680 { 681 this.DbConnection.Dispose(); 682 } 683 } 684 } 685 /// 686 /// Common sqlcommand 687 /// 688 internal class DbCommandCommon : IDisposable 689 { 690 /// 691 /// common dbcommand 692 /// 693 public DbCommand DbCommand { get; set; } 694 public DbCommandCommon(Opt_DataBaseType dataBaseType) 695 { 696 this.DbCommand = GetDbCommand(dataBaseType); 697 } 698 699 /// 700 /// Get DbCommand select database type 701 /// 702 /// 703 /// 704 private DbCommand GetDbCommand(Opt_DataBaseType dataBaseType) 705 { 706 switch (dataBaseType) 707 { 708 case Opt_DataBaseType.SqlServer: 709 return new SqlCommand(); 710 case Opt_DataBaseType.MySql: 711 return new MySqlCommand(); 712 case Opt_DataBaseType.Oracle: 713 return new OracleCommand(); 714 default: 715 return new SqlCommand(); 716 } 717 } 718 /// 719 /// must dispose after use 720 /// 721 public void Dispose() 722 { 723 if (this.DbCommand != null) 724 { 725 this.DbCommand.Dispose(); 726 } 727 } 728 } 729 /// 730 /// DbDataAdapterCommon 731 /// 732 internal class DbDataAdapterCommon : DbDataAdapter, IDisposable 733 { 734 public DbDataAdapter DbDataAdapter { get; set; } 735 public DbDataAdapterCommon(Opt_DataBaseType dataBaseType, DbCommand dbCommand) 736 { 737 //get dbAdapter 738 this.DbDataAdapter = GetDbAdapter(dataBaseType, dbCommand); 739 //provid select command 740 this.SelectCommand = dbCommand; 741 } 742 private DbDataAdapter GetDbAdapter(Opt_DataBaseType dataBaseType, DbCommand dbCommand) 743 { 744 switch (dataBaseType) 745 { 746 case Opt_DataBaseType.SqlServer: 747 return new SqlDataAdapter(); 748 case Opt_DataBaseType.MySql: 749 return new MySqlDataAdapter(); 750 case Opt_DataBaseType.Oracle: 751 return new OracleDataAdapter(); 752 default: 753 return new SqlDataAdapter(); 754 } 755 } 756 /// 757 /// must dispose after use 758 /// 759 public new void Dispose() 760 { 761 if (this.DbDataAdapter != null) 762 { 763 this.DbDataAdapter.Dispose(); 764 } 765 } 766 } 767 }
Db_Helper_DG简介:
本类分为 ExecuteNonQuery、ExecuteScalar、ExecuteScalar、ExecuteDataTable、ExecuteDataSet、ExecuteList Entity、ExecuteEntity七大部分,每一部分分为 无条件参数执行Sql语句或存储过程、SqlParameter[]参数执行Sql语句,Object[]参数执行存储过程三个重载方法。
方法的详细代码见上一条主代码Db_Helper_DG中折叠部分,这里对ExecuteListEntity和ExecuteEntity方法进行着重介绍。
ExecuteListEntity和ExecuteEntity,此二方法是为了将查询结果和Model即Entity实体进行映射所用,使用C#反射Reflect技术,进行将查询结果直接赋值成为了Entity或者List
ExecuteList方法通过二次封装,显式调用GetListFromDataSet方法,从DataSet结果集中遍历结果以进行赋值,代码如下:
1 public static ListGetListFromDataSet (DataSet ds) where Entity : class 2 { 3 List list = new List ();//实例化一个list对象 4 PropertyInfo[] propertyInfos = typeof(Entity).GetProperties(); //获取T对象的所有公共属性 5 6 DataTable dt = ds.Tables[0]; // 获取到ds的dt 7 if (dt.Rows.Count > 0) 8 { 9 //判断读取的行是否>0 即数据库数据已被读取 10 foreach (DataRow row in dt.Rows) 11 { 12 Entity model1 = System.Activator.CreateInstance ();//实例化一个对象,便于往list里填充数据 13 foreach (PropertyInfo propertyInfo in propertyInfos) 14 { 15 try 16 { 17 //遍历模型里所有的字段 18 if (row[propertyInfo.Name] != System.DBNull.Value) 19 { 20 //判断值是否为空,如果空赋值为null见else 21 if (propertyInfo.PropertyType.IsGenericType && propertyInfo.PropertyType.GetGenericTypeDefinition().Equals(typeof(Nullable<>))) 22 { 23 //如果convertsionType为nullable类,声明一个NullableConverter类,该类提供从Nullable类到基础基元类型的转换 24 NullableConverter nullableConverter = new NullableConverter(propertyInfo.PropertyType); 25 //将convertsionType转换为nullable对的基础基元类型 26 propertyInfo.SetValue(model1, Convert.ChangeType(row[propertyInfo.Name], nullableConverter.UnderlyingType), null); 27 } 28 else 29 { 30 propertyInfo.SetValue(model1, Convert.ChangeType(row[propertyInfo.Name], propertyInfo.PropertyType), null); 31 } 32 } 33 else 34 { 35 propertyInfo.SetValue(model1, null, null);//如果数据库的值为空,则赋值为null 36 } 37 } 38 catch (Exception) 39 { 40 propertyInfo.SetValue(model1, null, null);//如果数据库的值为空,则赋值为null 41 } 42 } 43 list.Add(model1);//将对象填充到list中 44 } 45 } 46 return list; 47 }
ExecuteEntity部分又分为从DataReader中获取和Linq从List
1 public static Entity GetEntityFromDataReader(DbDataReader reader) where Entity : class 2 { 3 Entity model = System.Activator.CreateInstance (); //实例化一个T类型对象 4 PropertyInfo[] propertyInfos = model.GetType().GetProperties(); //获取T对象的所有公共属性 5 using (reader) 6 { 7 if (reader.Read()) 8 { 9 foreach (PropertyInfo propertyInfo in propertyInfos) 10 { 11 //遍历模型里所有的字段 12 if (reader[propertyInfo.Name] != System.DBNull.Value) 13 { 14 //判断值是否为空,如果空赋值为null见else 15 if (propertyInfo.PropertyType.IsGenericType && propertyInfo.PropertyType.GetGenericTypeDefinition().Equals(typeof(Nullable<>))) 16 { 17 //如果convertsionType为nullable类,声明一个NullableConverter类,该类提供从Nullable类到基础基元类型的转换 18 NullableConverter nullableConverter = new NullableConverter(propertyInfo.PropertyType); 19 //将convertsionType转换为nullable对的基础基元类型 20 propertyInfo.SetValue(model, Convert.ChangeType(reader[propertyInfo.Name], nullableConverter.UnderlyingType), null); 21 } 22 else 23 { 24 propertyInfo.SetValue(model, Convert.ChangeType(reader[propertyInfo.Name], propertyInfo.PropertyType), null); 25 } 26 } 27 else 28 { 29 propertyInfo.SetValue(model, null, null);//如果数据库的值为空,则赋值为null 30 } 31 } 32 return model;//返回T类型的赋值后的对象 model 33 } 34 } 35 return default(Entity);//返回引用类型和值类型的默认值0或null 36 }
1 public static Entity GetEntityFromDataSet(DataSet ds) where Entity : class 2 { 3 return GetListFromDataSet (ds).FirstOrDefault(); 4 }
【系统测试】
在全部功能实现之余,下面我们进行代码测试环节。
1、MySql数据库操作
各种方式给Db_Helper_DG的链接字符串属性进行赋值,这里不再赘述。
根据测试表的设计进行新建对应的实体类:
1 public class TB_People 2 { 3 public Guid Uid { get; set; } 4 public string Name { get; set; } 5 public int Age { get; set; } 6 public int ClassId { get; set; } 7 }
填写好连接字符串,并给Db_Helper_DG类的ConnString_Default属性赋值后,我们直接调用方法进行查询操作。
调用静态方法ExecuteList以便直接映射到实体类:
1 ListpeopleList = Db_Helper_DG.ExecuteList ("select * from student where ClassId=?ClassId", System.Data.CommandType.Text, new MySqlParameter("?ClassId", 1)); 2 foreach (var item in peopleList) 3 { 4 Console.WriteLine(item.Name); 5 }
这里的MySql语句 select * from student where ClassId=?ClassId 然后参数化赋值 ?ClassId=1 进行查询。
结果如下:
可见,查询结果并无任何差池,自动映射到了实体类的属性。
2、SqlServer数据库操作
因为数据库结构MySql和SqlServer的结构是一致的,因此使用上述的实体类TB_People。
同样填写连接字符串,并给Db_Helper_DG类的ConnString_Default属性赋值后,我们直接调用方法进行查询操作。
然后我们修改Sql语句,并且修改为SqlServer传递参数方式进行查询:
1 ListpeopleList = Db_Helper_DG.ExecuteList ("select * from TB_People where ClassId=@ClassId", System.Data.CommandType.Text, new SqlParameter("@ClassId", 1)); 2 foreach (var item in peopleList) 3 { 4 Console.WriteLine(item.Name); 5 }
select * from TB_People where ClassId =1,ClassId按照SqlServer参数传递的方式进行传递。
可见,查询结果并无任何差池,自动映射到了实体类的属性。
3、Oracle由于本人当前Oracle环境问题,先不进行测试。