zoukankan      html  css  js  c++  java
  • 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->

     View Code

      2、主类代码Db_Helper_DG->

     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环境问题,先不进行测试。

  • 相关阅读:
    win服务大全 (转)
    给大家贴一点好东东 喜欢电影的朋友请看
    滚动字幕的制作 marquee
    嵌入式软件工程师读书计划总纲 转
    优秀男人的十五条标准[转]
    寒冷的冬天到了,我们开始画饼充饥
    如何用.NET创建Windows服务 [转]
    请教:如何进行存储过程的调试
    人际交往(转)
    用户控件 与 Response.Redirect 转向的问题
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/7615365.html
Copyright © 2011-2022 走看看