C#操作SqlServer MySql Oracle通用帮助类
C#操作SqlServer MySql Oracle通用帮助类
【前言】
作为一款成熟的面向对象高级编程语言,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 /// <summary>
4 /// SqlConnection
5 /// </summary>
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 /// <summary>
28 /// GetDataBase ConnectionString by database type and connection string -- private use
29 /// </summary>
30 /// <param name="dataBaseType"></param>
31 /// <param name="ConnString"></param>
32 /// <returns></returns>
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 /// <summary>
48 /// Must Close Connection after use
49 /// </summary>
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 /// <summary>
4 /// common dbcommand
5 /// </summary>
6 public DbCommand DbCommand { get; set; }
7 public DbCommandCommon(Opt_DataBaseType dataBaseType)
8 {
9 this.DbCommand = GetDbCommand(dataBaseType);
10 }
11
12 /// <summary>
13 /// Get DbCommand select database type
14 /// </summary>
15 /// <param name="dataBaseType"></param>
16 /// <returns></returns>
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 /// <summary>
32 /// must dispose after use
33 /// </summary>
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 /// <summary>
2 /// DbDataAdapterCommon
3 /// </summary>
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 /// <summary>
29 /// must dispose after use
30 /// </summary>
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->
2、主类代码Db_Helper_DG->
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<Entity>对象(此亦是ORM框架的核心)
ExecuteList方法通过二次封装,显式调用GetListFromDataSet方法,从DataSet结果集中遍历结果以进行赋值,代码如下:

1 public static List<Entity> GetListFromDataSet<Entity>(DataSet ds) where Entity : class
2 {
3 List<Entity> list = new List<Entity>();//实例化一个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<Entity>();//实例化一个对象,便于往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<Entity>获取第一条进行获取两种方式,由于DataReader有占用连接不释放的特点,在高并发的环境下使用并不友好,因此在实际生产环境中使用推荐使用第二种Linq获取List<Entity>的方式:

1 public static Entity GetEntityFromDataReader<Entity>(DbDataReader reader) where Entity : class
2 {
3 Entity model = System.Activator.CreateInstance<Entity>(); //实例化一个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<Entity>(DataSet ds) where Entity : class
2 {
3 return GetListFromDataSet<Entity>(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 List<TB_People> peopleList = Db_Helper_DG.ExecuteList<TB_People>("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 List<TB_People> peopleList = Db_Helper_DG.ExecuteList<TB_People>("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环境问题,先不进行测试。
C#操作SqlServer MySql Oracle通用帮助类的更多相关文章
- C#操作SqlServer MySql Oracle通用帮助类Db_Helper_DG(默认支持数据库读写分离、查询结果实体映射ORM)
[前言] 作为一款成熟的面向对象高级编程语言,C#在ADO.Net的支持上已然是做的很成熟,我们可以方便地调用ADO.Net操作各类关系型数据库,在使用了多年的Sql_Helper_DG后,由于项目需 ...
- sqlserver,mysql,oracle通用的模拟和改进的全文搜索算法
问:数据库效率最低的地方是什么? 答:表扫描 问:表扫描常见的情况是 答:like '%a%' 这类查询 如果使用全文检索引擎,又无法满足我们的需求的时候怎么办,比如要从 一个商品名称 "农 ...
- 针对SQLServer数据库的通用访问类
Web.config中代码 <configuration> <connectionStrings> <add name="connString" co ...
- java JDBC链接sqlserver/mysql/oracle
今天初学数据库的一些简单创建数据库和表,并进行简单的查询,插入. 接下学习的就是java工程中怎么链接数据库呢.主要的方法和用到的类如下. 切记,mysql需要的jar包 mysql-connecto ...
- jdbc连接sqlserver,mysql,oracle
class xxx{ private static String port = "1433"; private static String ip = "192.168.2 ...
- oracle通用帮助类
需要的dll( EntityFramework.6.0.0Oracle.ManagedDataAccess.12.1.2400System.Configuration.dllEmitMapper.1. ...
- SQL Server,MySQL,Oracle三者的区别
SQL Server,MySQL,Oracle三者的区别 2016-10-14 转自:SQL Server,MySQL,Oracle三者的区别 目录 1 Oracle.Sql Server.MySql ...
- mysql oracle postgresql 体系架构对比
2个角度sqlservermysqloracle 12cpostgresql如果从create database角度来看 那么一个实例是可以对应多个数据库的~如果从实例和磁盘上的数据库文件(数据文件. ...
- Mysql、SqlServer、Oracle三大数据库的区别
一.MySQL 优点: 体积小.速度快.总体拥有成本低,开源: 支持多种操作系统: 是开源数据库,提供的接口支持多种语言连接操作 : MySQL的核心程序采用完全的多线程编程.线程是轻量级的进程,它可 ...
随机推荐
- Android 上的 制表符(tab) —— 一个奇妙的字符 (二)
接到上回的说,主要是上回那个问题,我认为是android的bug,黎叔认为是cocos2dx的bug,叫我去提交bug.所以我又继续研究了下. 上回说到会调用java层的函数去创建一个image,然后 ...
- AngularJS渲染性能分析
作者:Jiang, Jilin AngularJS中,通过数据绑定.能够十分方便的构建页面.可是当面对复杂的循环嵌套结构时,渲染会遇到性能瓶颈.今天,我们将通过一些列实验,来測试AngularJS的渲 ...
- Android学习笔记进阶19之给图片加边框
//设置颜色 public void setColour(int color){ co = color; } //设置边框宽度 public void setBorderWidth(int width ...
- android图片特效处理之光照效果
这篇将讲到图片特效处理的光照效果.跟前面一样是对像素点进行处理,算法是通用的. 算法原理:图片上面的像素点按照给定圆心,按照圆半径的变化,像素点的RGB值分别加上相应的值作为当前点的RGB值. 例: ...
- php实现合并多个数组
php实现合并多个数组 一.总结 1.就是想c++和java里面合并数组那么简单,就是把多个数组的值赋值个一个啊,很简单 二.代码 合并多个数组,不用array_merge(),题目来于论坛. 思路: ...
- 初步使用RecyclerView实现瀑布流
先看效果 关于RecyclerView,真的是很强大. 个人觉得主要方便的地方是 1.直接可以设置条目布局,通过setLayoutManager LinearLayoutManager:线性布局,横向 ...
- 阿姆达尔定律(Amdahl's law)
首先给出阿姆达尔定律的数学公式描述: S(N)=1(1−p)+pN p:程序中可并行部分的程序在单核上执行时间的占比: N:处理器的数目(总的核心数) S(N):程序在 N 个处理器(总核心数)相对在 ...
- Angularjs: 封装layDate指令
[摘要]由于业务需要,将bootstrap-datetimepicker改成了layDate. layDate是一个较成熟且便于操作的jQuery日期插件,支持同一个视图内范围选择.封装成一个指令在多 ...
- linux监测tomcat服务
原文链接:https://blog.csdn.net/qq_37936542/article/details/81086928 项目上线之后,tomcat服务器有时候会莫名其妙的挂掉,利用shell写 ...
- actionbar-displayOptions 属性分析
displayOptions 这个属性主要是控制这actionbar 上返回按钮.标题等的显示.它作为 actionBarStyle 的一个item,如下 <style name="A ...