使用ado.net打造通用的数据库操作类
最近在项目中使用中碰到了这样一种情况,查询的数据是从Oracle中获取的,但是记录下来的数据是存在Sql Server中(企业Oracle数据库管理太严,没办法操作)。而且我在之前的工作中也碰到过使用SQLite数据库,就借这次机会写一个通用的类库。
我在网上搜到了一篇利用工厂模式实现的通用类库,我在参考该文章基础上,做了一些修改。本文最好有一些Ado.net的基础。
感谢埋头前进的码农 https://www.cnblogs.com/lifeil/archive/2013/04/16/3024161.html的文章。
1.首先创建数据库的枚举类型
1 public enum DbProviderType : byte 2 { 3 // <summary> 4 /// 微软 SqlServer 数据库 5 /// </summary> 6 SqlServer, 7 8 /// <summary> 9 /// 开源 MySql数据库 10 /// </summary> 11 MySql, 12 13 /// <summary> 14 /// 嵌入式轻型数据库 SQLite 15 /// </summary> 16 SQLite, 17 18 /// <summary> 19 /// 甲骨文 Oracle 20 /// </summary> 21 Oracle, 22 23 /// <summary> 24 /// 旧版微软的oracle组件,目前已经废弃 25 /// </summary> 26 OracleClient, 27 28 /// <summary> 29 /// 开放数据库互连 30 /// </summary> 31 ODBC, 32 33 /// <summary> 34 /// 面向不同的数据源的低级应用程序接口 35 /// </summary> 36 OleDb, 37 38 /// <summary> 39 /// 跨平台的关系数据库系统 Firebird 40 /// </summary> 41 Firebird, 42 43 /// <summary> 44 ///加州大学伯克利分校计算机系开发的关系型数据库 PostgreSql 45 /// </summary> 46 PostgreSql, 47 48 /// <summary> 49 /// IBM出口的一系列关系型数据库管理系统 DB2 50 /// </summary> 51 DB2, 52 53 /// <summary> 54 /// IBM公司出品的关系数据库管理系统(RDBMS)家族 Informix 55 /// </summary> 56 Informix, 57 58 /// <summary> 59 /// 微软推出的一个适用于嵌入到移动应用的精简数据库产品 SqlServerCe 60 /// </summary> 61 SqlServerCe 62 }
2.创建好后,我们再设计一个ProviderFactory类,该类可以根据传过来的DbProviderType,创建不同的DbProviderFactory 对象,该对象用于一般的数据库操作。
1 public class ProviderFactory 2 { 3 /// <summary> 4 /// 保存每种数据访问方式对应的程序集名称 5 /// </summary> 6 private static Dictionary<MyHelper.Define.DbProviderType,string> providerInvariantNames =new Dictionary<MyHelper.Define.DbProviderType,string>(); 7 8 /// <summary> 9 /// 保存已经生成的DbProviderFactory对象 10 /// </summary> 11 private readonly static Dictionary<MyHelper.Define.DbProviderType, DbProviderFactory> providerFactoies = new Dictionary<MyHelper.Define.DbProviderType, DbProviderFactory>(20); 12 13 /// <summary> 14 /// 加载已知的访问类型与名称 15 /// </summary> 16 static ProviderFactory() 17 { 18 providerInvariantNames.Add(MyHelper.Define.DbProviderType.SqlServer, "System.Data.SqlClient"); 19 providerInvariantNames.Add(MyHelper.Define.DbProviderType.OleDb, "System.Data.OleDb"); 20 providerInvariantNames.Add(MyHelper.Define.DbProviderType.ODBC, "System.Data.ODBC"); 21 providerInvariantNames.Add(MyHelper.Define.DbProviderType.OracleClient, "System.Data.OracleClient");//已经废弃 22 providerInvariantNames.Add(MyHelper.Define.DbProviderType.Oracle, "Oracle.ManagedDataAccess.Client"); //需要安装Oracle.ManagedDataAccess插件,否则无效 23 providerInvariantNames.Add(MyHelper.Define.DbProviderType.MySql, "MySql.Data.MySqlClient"); 24 providerInvariantNames.Add(MyHelper.Define.DbProviderType.SQLite, "System.Data.SQLite"); //注意在Nuget加入SQLite程序集 25 //出现错误的话,参考https://www.cnblogs.com/leleroyn/archive/2011/03/24/1993627.html 26 //<remove invariant="System.Data.SQLite"/> 27 //<add name="SQLite Data Provider" invariant="System.Data.SQLite" description=".Net Framework Data Provider for SQLite" type="System.Data.SQLite.SQLiteFactory, System.Data.SQLite" /> 28 providerInvariantNames.Add(MyHelper.Define.DbProviderType.Firebird, "FirebirdSql.Data.Firebird"); 29 providerInvariantNames.Add(MyHelper.Define.DbProviderType.PostgreSql, "Npgsql"); 30 providerInvariantNames.Add(MyHelper.Define.DbProviderType.DB2, "IBM.Data.DB2.iSeries"); 31 providerInvariantNames.Add(MyHelper.Define.DbProviderType.Informix, "IBM.Data.Informix"); 32 providerInvariantNames.Add(MyHelper.Define.DbProviderType.SqlServerCe, "System.Data.SqlServerCe"); 33 } 34 35 public static DbProviderFactory GetDbProviderFactory(MyHelper.Define.DbProviderType providerType) 36 { 37 if (!providerFactoies.ContainsKey(providerType)) 38 { 39 var factory = BuildDbProviderFactory(providerType); //生成DbProviderFactory对象 40 providerFactoies.Add(providerType, factory); //加入到字典中 41 } 42 return providerFactoies[providerType]; 43 } 44 45 /// <summary> 46 /// 生成DbProviderFactory对象 47 /// </summary> 48 /// <param name="providerType"></param> 49 /// <returns></returns> 50 private static DbProviderFactory BuildDbProviderFactory(MyHelper.Define.DbProviderType providerType) 51 { 52 string provideName = providerInvariantNames[providerType]; //程序集名称; 53 DbProviderFactory factory = null; 54 try 55 { 56 factory = DbProviderFactories.GetFactory(provideName); 57 } 58 catch (Exception ex) 59 { 60 factory = null; 61 } 62 return factory; 63 }
3.创建DbHelper类。
1 public class DbHelper 2 { 3 private DbProviderFactory _providerFactory; 4 private string _connectionString = null; //保存连接字符串 5 6 /// <summary> 7 /// 生成DbProviderFactory对象 8 /// </summary> 9 /// <param name="connectionString">连接字符串</param> 10 /// <param name="providerType">需要生成的DbProviderFactory对象</param> 11 public DbHelper(string connectionString,MyHelper.Define.DbProviderType providerType) 12 { 13 if (string.IsNullOrEmpty(connectionString)) //连接字符串不能为空 14 { 15 throw new ArgumentException("connectionString is not null"); 16 } 17 _providerFactory = ProviderFactory.GetDbProviderFactory(providerType); //获取到生成的DbProviderFactory对象 18 _connectionString = connectionString; 19 if (_providerFactory == null) 20 { 21 throw new ArgumentException("can't build DbProviderFactory, please check DbProviderType "); 22 } 23 } 24 25 /// <summary> 26 /// 判断数据库是否可以打开 27 /// </summary> 28 /// <returns></returns> 29 public bool CanOpen() 30 { 31 var dbConnection= _providerFactory.CreateConnection(); 32 dbConnection.ConnectionString = _connectionString; 33 try 34 { 35 dbConnection.Open(); //打开连接 36 return true; 37 38 } 39 catch (Exception ex) 40 { 41 return false; 42 } 43 finally 44 { 45 dbConnection.Close(); //关闭连接 46 } 47 } 48 49 /// <summary> 50 /// 51 /// </summary> 52 /// <returns></returns> 53 public DbConnection GetDbConnection() 54 { 55 var connection= _providerFactory.CreateConnection(); 56 connection.ConnectionString = _connectionString; 57 return connection; 58 } 59 60 /// <summary> 61 /// 执行增删改的方法 62 /// </summary> 63 /// <param name="sqlString">sql语句</param> 64 /// <param name="dbParameters">参数</param> 65 /// <param name="commandType">执行方式,是Sql语句还是存储过程</param> 66 /// <returns></returns> 67 public int ExecuteNonQuery(string sqlString ,DbParameter[] dbParameters,CommandType commandType) 68 { 69 int result; 70 using (DbConnection connection = GetDbConnection()) 71 { 72 using (DbCommand command = CreateDbQueryCommand(connection, sqlString, dbParameters, commandType)) 73 { 74 connection.Open(); 75 result= command.ExecuteNonQuery(); 76 connection.Close(); 77 } 78 } 79 80 return result; 81 } 82 83 84 /// <summary> 85 /// 执行查询语句,返回DataSet 86 /// </summary> 87 /// <param name="sqlString"></param> 88 /// <param name="dbParameters"></param> 89 /// <param name="commandType"></param> 90 /// <returns></returns> 91 public DataSet ExecuteQuery(string sqlString, DbParameter[] dbParameters, CommandType commandType) 92 { 93 DataSet dataSet=new DataSet(); 94 using (DbConnection connection = GetDbConnection()) 95 { 96 using(DbDataAdapter adapter=_providerFactory.CreateDataAdapter()) 97 { 98 adapter.SelectCommand=CreateDbQueryCommand(connection,sqlString,dbParameters,commandType); 99 connection.Open(); 100 adapter.Fill(dataSet); 101 connection.Close(); 102 } 103 } 104 return dataSet; 105 } 106 107 private DbCommand CreateDbQueryCommand(DbConnection connection, string sqlString, IDbDataParameter[] dbParameters, CommandType commandType) 108 { 109 return CreateDbCommand(connection, sqlString, dbParameters, commandType, null); 110 } 111 112 /// <summary> 113 /// 创建DbCommand对象 114 /// </summary> 115 /// <param name="connection">DbConnection对象</param> 116 /// <param name="sqlString">查询语句</param> 117 /// <param name="dbParameters">参数</param> 118 /// <param name="commandType">类型</param> 119 /// <param name="dbTransaction">事务</param> 120 /// <returns></returns> 121 public DbCommand CreateDbCommand(DbConnection connection, string sqlString, IDbDataParameter[] dbParameters, CommandType commandType,DbTransaction dbTransaction) 122 { 123 DbCommand command = _providerFactory.CreateCommand(); 124 if (dbTransaction != null) 125 { 126 command.Transaction = dbTransaction; 127 } 128 command.CommandText = sqlString; 129 command.CommandType = commandType; 130 command.Connection = connection; 131 if (dbParameters != null) 132 { 133 command.Parameters.AddRange(dbParameters); 134 } 135 return command; 136 } 137 138 139 /// <summary> 140 /// 返回第一行第一列的数据,一般用于执行聚合操作的语句 141 /// </summary> 142 /// <param name="sqlString">查询语句</param> 143 /// <param name="dbParameters">参数</param> 144 /// <param name="commandType">Sql语句还是存储过程</param> 145 /// <returns></returns> 146 public object ExecuteScalar(string sqlString, DbParameter[] dbParameters, CommandType commandType) 147 { 148 object result; 149 using (DbConnection connection = GetDbConnection()) 150 { 151 using (DbCommand command = CreateDbQueryCommand(connection, sqlString, dbParameters, commandType)) 152 { 153 connection.Open(); 154 result = command.ExecuteScalar(); 155 connection.Close(); 156 } 157 } 158 return result; 159 }
方法的说明已经的很清楚了,有点Ado.net基础的同学应该都能看的懂。
下面进入我们的测试阶段,在这儿我们重点以Sql Server做测试,也会测试一下Oracle数据库和SQLite数据库。
首先我们创建一个TestDb的数据库,再创建一张Users表。
我们在创建一个存储过程,该存过过程根据传进来的ID值,返回Name字段。
下面是存储过程的代码:
1 Create procedure [dbo].[GetUser] 2 @id varchar(30), 3 @name varchar(30) output 4 as 5 begin 6 select @name=name from Users where id=@id 7 end
现在开始测试。
首先我们先执行ExecuteQuery方法,该方法返回DataSet对象。
1 var connectionString = @"Server=.;Initial Catalog=TestDB;User ID=sa;Password=123456;"; 2 DbHelper dbHelper = new DbHelper(connectionString, MyHelper.Define.DbProviderType.SqlServer); 3 string text = "select * from users "; 4 5 var usersDataSet = dbHelper.ExecuteQuery(text, null, CommandType.Text); 6 7 for (int i = 0; i < usersDataSet.Tables[0].Rows.Count; i++) 8 { 9 Console.WriteLine("ID:{0},名字:{1}", usersDataSet.Tables[0].Rows[i][0], usersDataSet.Tables[0].Rows[i][1]); 10 } 11 12 13 Console.ReadKey();
结果:
执行ExecuteScalar方法,这儿我们查询出Users这张表的总数量。
1 var connectionString = @"Server=.;Initial Catalog=TestDB;User ID=sa;Password=123456;"; 2 DbHelper dbHelper = new DbHelper(connectionString, MyHelper.Define.DbProviderType.SqlServer); 3 string text = "select count(*) from users "; 4 5 var count = (int)dbHelper.ExecuteScalar(text, null, CommandType.Text); 6 Console.WriteLine("总数量:" + count.ToString()); 7 8 Console.ReadKey();
结果
执行ExecuteNonQuery方法,在这儿我们执行带有返回参数的存储过程。
1 var connectionString = @"Server=.;Initial Catalog=TestDB;User ID=sa;Password=123456;"; 2 DbHelper dbHelper = new DbHelper(connectionString, MyHelper.Define.DbProviderType.SqlServer); 3 string text = "GetUser "; 4 DbParameter[] parameters = new DbParameter[] 5 { 6 new SqlParameter("@id", SqlDbType.VarChar){ Value="1"}, 7 new SqlParameter("@name", SqlDbType.VarChar){ Direction=ParameterDirection.Output,Size=30} 8 }; 9 dbHelper.ExecuteNonQuery(text, parameters, CommandType.StoredProcedure); 10 Console.WriteLine("名字:" + parameters[1].Value); 11 12 Console.ReadKey();
上面的三种方法,我们都已经测试完成,没有任何问题。
下面我们来替换使用其他数据库继续测试。
Oracle数据库:
在测试前需要在Nuget中加入Oracle.ManagedDataAccess程序集,否则会出现错误。
1 var connectionString = @"Password=lisi;User ID=lisi;Data Source=(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=192.168.229.138) 2 (PORT=1521)))(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=MLDN)))"; 3 DbHelper dbHelper = new DbHelper(connectionString, MyHelper.Define.DbProviderType.Oracle); 4 string text = "select * from users "; 5 6 var usersDataSet = dbHelper.ExecuteQuery(text, null, CommandType.Text); 7 8 for (int i = 0; i < usersDataSet.Tables[0].Rows.Count; i++) 9 { 10 Console.WriteLine("ID:{0},名字:{1}", usersDataSet.Tables[0].Rows[i][0], usersDataSet.Tables[0].Rows[i][1]); 11 } 12 13 14 Console.ReadKey();
结果
OK,Oracle也没问题。
下面试试看SQLite数据库。
该方法也需要在Nuget中加入SQLite的的插件:
如果不加入的话,会出现以下错误:
在装好后,不一定能使用起来,还是出现以上错误
则在Config文件DbProviderFactories节点中加入一段代码就可以了。
<remove invariant="System.Data.SQLite"/> <add name="SQLite Data Provider" invariant="System.Data.SQLite" description=".Net Framework Data Provider for SQLite" type="System.Data.SQLite.SQLiteFactory, System.Data.SQLite" />
代码:
1 var connectionString = @"data source=mydb.db"; 2 DbHelper dbHelper = new DbHelper(connectionString, MyHelper.Define.DbProviderType.SQLite); 3 4 //string text = "create table users(id varchar(20),name varchar(20)); "; 5 //dbHelper.ExecuteNonQuery(text, null, CommandType.Text); //创建表 6 7 //string sql1 = "insert into users values('1','zhangsan')"; 8 //string sql2 = "insert into users values('2','lisi')"; 9 //dbHelper.ExecuteNonQuery(sql1, null, CommandType.Text); //创建表 10 //dbHelper.ExecuteNonQuery(sql2, null, CommandType.Text); //创建表 11 12 string selectSql = "select * from users"; 13 var usersDataSet = dbHelper.ExecuteQuery(selectSql, null, CommandType.Text); 14 for (int i = 0; i < usersDataSet.Tables[0].Rows.Count; i++) 15 { 16 Console.WriteLine("ID:{0},名字:{1}", usersDataSet.Tables[0].Rows[i][0], usersDataSet.Tables[0].Rows[i][1]); 17 } 18 19 Console.ReadKey();
在代码中我加入了创建表和插入数据的语句,该段代码被我注释了,如果想要测试的话,执行一次就可以了。
以上初步测试了SQL Server,Oracle和SQLite三种数据库。
参考文章:
https://www.cnblogs.com/leleroyn/archive/2011/03/24/1993627.html
https://www.cnblogs.com/gguozhenqian/p/4262813.html
https://www.cnblogs.com/lifeil/archive/2013/04/16/3024161.html