本文章为原创内容,如需转载,请注明作者及出处,谢谢!


一、在System.Data.Common命名空间下,存在这样的一个类:

    //
// 摘要:
// 表示一组方法,这些方法用于创建提供程序对数据源类的实现的实例。
public abstract class DbProviderFactory
{
//
// 摘要:
// 初始化 System.Data.Common.DbProviderFactory 类的新实例。
protected DbProviderFactory(); //
// 摘要:
// 指定特定的 System.Data.Common.DbProviderFactory 是否支持 System.Data.Common.DbDataSourceEnumerator
// 类。
//
// 返回结果:
// 如果 System.Data.Common.DbProviderFactory 的实例支持 System.Data.Common.DbDataSourceEnumerator
// 类,则为 true;否则为 false。
public virtual bool CanCreateDataSourceEnumerator { get; } //
// 摘要:
// 返回实现 System.Data.Common.DbCommand 类的提供程序的类的一个新实例。
//
// 返回结果:
// System.Data.Common.DbCommand 的新实例。
public virtual DbCommand CreateCommand();
//
// 摘要:
// 返回实现 System.Data.Common.DbCommandBuilder 类的提供程序的类的一个新实例。
//
// 返回结果:
// System.Data.Common.DbCommandBuilder 的新实例。
public virtual DbCommandBuilder CreateCommandBuilder();
//
// 摘要:
// 返回实现 System.Data.Common.DbConnection 类的提供程序的类的一个新实例。
//
// 返回结果:
// System.Data.Common.DbConnection 的新实例。
public virtual DbConnection CreateConnection();
//
// 摘要:
// 返回实现 System.Data.Common.DbConnectionStringBuilder 类的提供程序的类的一个新实例。
//
// 返回结果:
// System.Data.Common.DbConnectionStringBuilder 的新实例。
public virtual DbConnectionStringBuilder CreateConnectionStringBuilder();
//
// 摘要:
// 返回实现 System.Data.Common.DbDataAdapter 类的提供程序的类的一个新实例。
//
// 返回结果:
// System.Data.Common.DbDataAdapter 的新实例。
public virtual DbDataAdapter CreateDataAdapter();
//
// 摘要:
// 返回实现 System.Data.Common.DbDataSourceEnumerator 类的提供程序的类的一个新实例。
//
// 返回结果:
// System.Data.Common.DbDataSourceEnumerator 的新实例。
public virtual DbDataSourceEnumerator CreateDataSourceEnumerator();
//
// 摘要:
// 返回实现 System.Data.Common.DbParameter 类的提供程序的类的一个新实例。
//
// 返回结果:
// System.Data.Common.DbParameter 的新实例。
public virtual DbParameter CreateParameter();
//
// 摘要:
// 返回提供程序的类的新实例,该实例可实现提供程序的 System.Security.CodeAccessPermission 类的版本。
//
// 参数:
// state:
// System.Security.Permissions.PermissionState 值之一。
//
// 返回结果:
// 指定 System.Security.Permissions.PermissionState 的 System.Security.CodeAccessPermission
// 对象。
public virtual CodeAccessPermission CreatePermission(PermissionState state);
}

我们可以看到,在此类中,有很多用于创建数据库相关对象的类型,如DbConnection,DbCommand,DbDataAdapter等。

而且,实现诸如SqlConnection、SqlCommand、SqlDataAdapter(这里用的是SQL Server)的类型,都分别继承自DbConnection,DbCommand,DbDataAdapter,

因此,我们可以使用DbProviderFactory来创建我们想要的、可实现任何数据库的DbHelper。

二、实现基本的DbHelper帮助类

1、我们将DbHelper定义为抽象类,并在类中提供一个抽象可读属性,名称叫DbProviderFactory,返回类型为DbProviderFactory(注:名称与返回类型可以为一样,也可以不一样),

2、我们利用在该抽象类实现的子类中重写DbProviderFactory方法,并在子类的构造函数中为该属性赋值,该值就是已经实现了具体数据库类型的DbProviderFactory。

定义的代码参考如下:

    public abstract class DbHelper
{
public abstract DbProviderFactory DbProviderFactory { get; }
}

3、我们为该抽象类编写一个构造函数,传进去的参数为连接字符串,并将其存储在可读的ConnectionString字段里,代码如下:

    public abstract class DbHelper
{
public DbHelper(string connectionString)
{
ConnectionString = connectionString;
}
public string ConnectionString { get; }
public abstract DbProviderFactory DbProviderFactory { get; }
}

4、在DbHelper编写一些用于实现数据库相关操作的方法,这里就用到了DbProviderFactory类中的方法,以下方法仅供参考,具体请参照其他完整的DbHelp帮助类,

DbHelper完整代码如下:

//帮助类的基类(抽象类)
public abstract class DbHelper
{
public DbHelper(string connectionString)
{
ConnectionString = connectionString;
} public abstract DbProviderFactory DbProviderFactory { get; } public string ConnectionString { get; } //以下实现的帮助类方法,仅供该例子使用,具体请参照其他完整的DbHelp帮助类
private void ThrowExceptionIfLengthNotEqual(string[] sqls, params DbParameter[][] parameters)
{
if (parameters.GetLength() != && sqls.Length != parameters.GetLength()) throw new ArgumentException($"一维数组{nameof(sqls)}的长度与二维数组{nameof(parameters)}长度的第一维长度不一致");
} private T[] Execute<T>(string[] sqls, CommandType commandType = CommandType.Text, ExecuteMode executeMode = ExecuteMode.NonQuery, params DbParameter[][] parameters)
{
ThrowExceptionIfLengthNotEqual(sqls, parameters);
if(executeMode == ExecuteMode.NonQuery && typeof(T) != typeof(int)) throw new InvalidCastException("使用NonQuery模式时,必须将类型T指定为int");
using (DbConnection connection = DbProviderFactory.CreateConnection())
using (DbCommand command = DbProviderFactory.CreateCommand())
{
connection.ConnectionString = ConnectionString;
connection.Open();
command.Connection = connection;
command.CommandType = commandType;
DbTransaction transaction = connection.BeginTransaction();
command.Transaction = transaction;
try
{
List<T> resultList = new List<T>();
for (int i = ; i < sqls.Length; i++)
{
command.CommandText = sqls[i];
if (parameters.GetLength() != )
{
command.Parameters.Clear();
command.Parameters.AddRange(parameters[i]);
}
object result = null;
switch (executeMode)
{
case ExecuteMode.NonQuery:
result = command.ExecuteNonQuery(); break;
case ExecuteMode.Scalar:
result = command.ExecuteScalar(); break;
default: throw new NotImplementedException();
}
resultList.Add((T)Convert.ChangeType(result, typeof(T)));
}
transaction.Commit();
return resultList.ToArray();
}
catch
{
transaction.Rollback();
throw;
}
}
} public int ExecuteNonQuery(string sql, params DbParameter[] parameter) => ExecuteNonQuery(new string[] { sql }, new DbParameter[][] { parameter })[]; public int[] ExecuteNonQuery(string[] sqls, params DbParameter[][] parameters)=> Execute<int>(sqls, CommandType.Text, ExecuteMode.NonQuery,parameters); public int ExecuteNonQueryWithProc(string sql, params DbParameter[] parameter) => ExecuteNonQueryWithProc(new string[] { sql }, new DbParameter[][] { parameter })[]; public int[] ExecuteNonQueryWithProc(string[] sqls, params DbParameter[][] parameters) => Execute<int>(sqls, CommandType.StoredProcedure, ExecuteMode.NonQuery, parameters); public T ExecuteScalar<T>(string sql, params DbParameter[] parameter) => ExecuteNonQuery<T>(new string[] { sql }, new DbParameter[][] { parameter })[]; public T[] ExecuteNonQuery<T>(string[] sqls, params DbParameter[][] parameters) => Execute<T>(sqls, CommandType.Text,ExecuteMode.Scalar, parameters); public T ExecuteScalarWithProc<T>(string sql, params DbParameter[] parameter) => ExecuteNonQuery<T>(new string[] { sql }, new DbParameter[][] { parameter })[]; public T[] ExecuteNonQueryWithProc<T>(string[] sqls, params DbParameter[][] parameters) => Execute<T>(sqls, CommandType.StoredProcedure, ExecuteMode.Scalar, parameters); enum ExecuteMode
{
NonQuery,Scalar
} private DataTable[] Fill(string[] selectSqls, CommandType commandType = CommandType.Text, params DbParameter[][] parameters)
{
ThrowExceptionIfLengthNotEqual(selectSqls, parameters);
using (DbConnection connection = DbProviderFactory.CreateConnection())
using (DbDataAdapter adapter = DbProviderFactory.CreateDataAdapter())
using (DbCommand command = DbProviderFactory.CreateCommand())
{
connection.ConnectionString = ConnectionString;
connection.Open();
command.Connection = connection;
command.CommandType = commandType;
adapter.SelectCommand = command;
List<DataTable> resultList = new List<DataTable>();
for (int i = ; i < selectSqls.Length; i++)
{
command.CommandText = selectSqls[i];
if (parameters.GetLength() != )
{
command.Parameters.Clear();
command.Parameters.AddRange(parameters[i]);
}
DataTable table = new DataTable();
adapter.Fill(table);
resultList.Add(table);
}
return resultList.ToArray();
}
} public DataTable Fill(string selectSql, params DbParameter[] parameter) => Fill(new string[] { selectSql }, new DbParameter[][] { parameter })[]; public DataTable[] Fill(string[] selectSqls, params DbParameter[][] parameters) => Fill(selectSqls, CommandType.Text, parameters); public DataTable FillWithProc(string selectSql, params DbParameter[] parameter) => FillWithProc(new string[] { selectSql }, new DbParameter[][] { parameter })[]; public DataTable[] FillWithProc(string[] selectSqls, params DbParameter[][] parameters) => Fill(selectSqls, CommandType.StoredProcedure, parameters);
}

三、实现具体的数据库帮助类

1、实现Sql Server的帮助类,具体方法:只要重写DbHelper类的DbProviderFactory属性并在构造函数为其赋值即可,其他的数据库帮助类亦是如此,

代码如下:

    //用于Sql Server的帮助类
public class SqlClientHelper : DbHelper
{
public SqlClientHelper(string connectionString) : base(connectionString)
{
this.DbProviderFactory = SqlClientFactory.Instance;
}
public override DbProviderFactory DbProviderFactory { get; }
}

2、参照以上,实现SQLite帮助类如下:

    //用于SQLite的帮助类
public class SQLiteHelper : DbHelper
{
public SQLiteHelper(string connectionString) : base(connectionString)
{
DbProviderFactory = SQLiteFactory.Instance;
}
public override DbProviderFactory DbProviderFactory { get; }
}

3、其他数据库的帮助类,正如以上所说的,只要重写DbHelper类的DbProviderFactory属性并在构造函数为其赋值即可。

四、示例演示

使用前,必须引用了System.Data.SQLite,具体请参考一下文章:

使用C#创建SQLite控制台应用程序

编写的客户端代码,如下:

    class Program
{
//客户端调用
static void Main(string[] args)
{
string fileName = "Test.db";
if (File.Exists(fileName)) File.Delete(fileName);
SQLiteConnection.CreateFile(fileName);
SQLiteHelper helper = new SQLiteHelper($"Data Source = {fileName}");
helper.ExecuteNonQuery("CREATE TABLE IF NOT EXISTS Info(ID integer PRIMARY KEY AUTOINCREMENT, Guid text)");
List<string> sqlList = new List<string>();
for (int i = ; i < ; i++)
{
sqlList.Add($"INSERT INTO Info VALUES(null,'{Guid.NewGuid()}')");
}
helper.ExecuteNonQuery(sqlList.ToArray());
DataTable table = helper.Fill("SELECT * FROM Info");
table.Rows.Cast<DataRow>().ToList().ForEach(x => Console.WriteLine($"{x[0]}\t{x[1]}"));
Console.ReadKey();
}
}

输出的结果如下:

五、完整代码如下:

using System;
using System.Linq;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Data.SqlClient;
using System.Data.SQLite;
using System.IO; namespace ConsoleApp
{
class Program
{
//客户端调用
static void Main(string[] args)
{
string fileName = "Test.db";
if (File.Exists(fileName)) File.Delete(fileName);
SQLiteConnection.CreateFile(fileName);
SQLiteHelper helper = new SQLiteHelper($"Data Source = {fileName}");
helper.ExecuteNonQuery("CREATE TABLE IF NOT EXISTS Info(ID integer PRIMARY KEY AUTOINCREMENT, Guid text)");
List<string> sqlList = new List<string>();
for (int i = ; i < ; i++)
{
sqlList.Add($"INSERT INTO Info VALUES(null,'{Guid.NewGuid()}')");
}
helper.ExecuteNonQuery(sqlList.ToArray());
DataTable table = helper.Fill("SELECT * FROM Info");
table.Rows.Cast<DataRow>().ToList().ForEach(x => Console.WriteLine($"{x[0]}\t{x[1]}"));
Console.ReadKey();
}
} //用于Sql Server的帮助类
public class SqlClientHelper : DbHelper
{
public SqlClientHelper(string connectionString) : base(connectionString)
{
this.DbProviderFactory = SqlClientFactory.Instance;
}
public override DbProviderFactory DbProviderFactory { get; }
} //用于SQLite的帮助类
public class SQLiteHelper : DbHelper
{
public SQLiteHelper(string connectionString) : base(connectionString)
{
DbProviderFactory = SQLiteFactory.Instance;
}
public override DbProviderFactory DbProviderFactory { get; }
} //--------------------------------------------------------------------------------
//其他数据库的帮助类,只要重写DbHelper类的DbProviderFactory属性并在构造函数为其赋值即可
//-------------------------------------------------------------------------------- //帮助类的基类(抽象类)
public abstract class DbHelper
{
public DbHelper(string connectionString)
{
ConnectionString = connectionString;
} public abstract DbProviderFactory DbProviderFactory { get; } public string ConnectionString { get; } //以下实现的帮助类方法,仅供该例子使用,具体请参照其他完整的DbHelp帮助类
private void ThrowExceptionIfLengthNotEqual(string[] sqls, params DbParameter[][] parameters)
{
if (parameters.GetLength() != && sqls.Length != parameters.GetLength()) throw new ArgumentException($"一维数组{nameof(sqls)}的长度与二维数组{nameof(parameters)}长度的第一维长度不一致");
} private T[] Execute<T>(string[] sqls, CommandType commandType = CommandType.Text, ExecuteMode executeMode = ExecuteMode.NonQuery, params DbParameter[][] parameters)
{
ThrowExceptionIfLengthNotEqual(sqls, parameters);
if(executeMode == ExecuteMode.NonQuery && typeof(T) != typeof(int)) throw new InvalidCastException("使用NonQuery模式时,必须将类型T指定为int");
using (DbConnection connection = DbProviderFactory.CreateConnection())
using (DbCommand command = DbProviderFactory.CreateCommand())
{
connection.ConnectionString = ConnectionString;
connection.Open();
command.Connection = connection;
command.CommandType = commandType;
DbTransaction transaction = connection.BeginTransaction();
command.Transaction = transaction;
try
{
List<T> resultList = new List<T>();
for (int i = ; i < sqls.Length; i++)
{
command.CommandText = sqls[i];
if (parameters.GetLength() != )
{
command.Parameters.Clear();
command.Parameters.AddRange(parameters[i]);
}
object result = null;
switch (executeMode)
{
case ExecuteMode.NonQuery:
result = command.ExecuteNonQuery(); break;
case ExecuteMode.Scalar:
result = command.ExecuteScalar(); break;
default: throw new NotImplementedException();
}
resultList.Add((T)Convert.ChangeType(result, typeof(T)));
}
transaction.Commit();
return resultList.ToArray();
}
catch
{
transaction.Rollback();
throw;
}
}
} public int ExecuteNonQuery(string sql, params DbParameter[] parameter) => ExecuteNonQuery(new string[] { sql }, new DbParameter[][] { parameter })[]; public int[] ExecuteNonQuery(string[] sqls, params DbParameter[][] parameters)=> Execute<int>(sqls, CommandType.Text, ExecuteMode.NonQuery,parameters); public int ExecuteNonQueryWithProc(string sql, params DbParameter[] parameter) => ExecuteNonQueryWithProc(new string[] { sql }, new DbParameter[][] { parameter })[]; public int[] ExecuteNonQueryWithProc(string[] sqls, params DbParameter[][] parameters) => Execute<int>(sqls, CommandType.StoredProcedure, ExecuteMode.NonQuery, parameters); public T ExecuteScalar<T>(string sql, params DbParameter[] parameter) => ExecuteNonQuery<T>(new string[] { sql }, new DbParameter[][] { parameter })[]; public T[] ExecuteNonQuery<T>(string[] sqls, params DbParameter[][] parameters) => Execute<T>(sqls, CommandType.Text,ExecuteMode.Scalar, parameters); public T ExecuteScalarWithProc<T>(string sql, params DbParameter[] parameter) => ExecuteNonQuery<T>(new string[] { sql }, new DbParameter[][] { parameter })[]; public T[] ExecuteNonQueryWithProc<T>(string[] sqls, params DbParameter[][] parameters) => Execute<T>(sqls, CommandType.StoredProcedure, ExecuteMode.Scalar, parameters); enum ExecuteMode
{
NonQuery,Scalar
} private DataTable[] Fill(string[] selectSqls, CommandType commandType = CommandType.Text, params DbParameter[][] parameters)
{
ThrowExceptionIfLengthNotEqual(selectSqls, parameters);
using (DbConnection connection = DbProviderFactory.CreateConnection())
using (DbDataAdapter adapter = DbProviderFactory.CreateDataAdapter())
using (DbCommand command = DbProviderFactory.CreateCommand())
{
connection.ConnectionString = ConnectionString;
connection.Open();
command.Connection = connection;
command.CommandType = commandType;
adapter.SelectCommand = command;
List<DataTable> resultList = new List<DataTable>();
for (int i = ; i < selectSqls.Length; i++)
{
command.CommandText = selectSqls[i];
if (parameters.GetLength() != )
{
command.Parameters.Clear();
command.Parameters.AddRange(parameters[i]);
}
DataTable table = new DataTable();
adapter.Fill(table);
resultList.Add(table);
}
return resultList.ToArray();
}
} public DataTable Fill(string selectSql, params DbParameter[] parameter) => Fill(new string[] { selectSql }, new DbParameter[][] { parameter })[]; public DataTable[] Fill(string[] selectSqls, params DbParameter[][] parameters) => Fill(selectSqls, CommandType.Text, parameters); public DataTable FillWithProc(string selectSql, params DbParameter[] parameter) => FillWithProc(new string[] { selectSql }, new DbParameter[][] { parameter })[]; public DataTable[] FillWithProc(string[] selectSqls, params DbParameter[][] parameters) => Fill(selectSqls, CommandType.StoredProcedure, parameters);
}
}

[C#]实现任何数据库类型的DbHelper帮助类的更多相关文章

  1. Winform开发框架中实现同时兼容多种数据库类型处理

    在很多应用系统里面,虽然一般采用一种数据库运行,但是由于各种情况的需要,可能业务系统会部署在不同类型的数据库上,如果开发的系统能够很方便支持多种数据库的切换,那可以为我们减少很多烦恼,同时提高系统的适 ...

  2. Winform开发框架中实现多种数据库类型切换以及分拆数据库的支持

    在很多应用系统里面,虽然一般采用一种数据库运行,但是由于各种情况的需要,可能业务系统会部署在不同类型的数据库上,如果开发的系统能够很方便支持多种数据库的切换,那可以为我们减少很多烦恼,同时提高系统的适 ...

  3. RDIFramework.NET 框架兼容各种数据库类型事务使用范例参考

    RDIFramework.NET 框架兼容各种数据库类型事务使用范例参考 RDIFramwork.NET框架对数据库的事务做了很好的控制,对多表或多条语句需要在同一事务执行提供了很好的支持,同时支持任 ...

  4. atitit. hb 原生sql跨数据库解决原理 获得hb 数据库类型运行期获得Dialect

    atitit. hb 原生sql跨数据库解决原理 获得hb 数据库类型运行期获得Dialect   #-----原理 Hibernate 运行期获得Dialect   2010-07-28 12:59 ...

  5. Java与数据库类型对照表

     数据库类型  Java类型  INTEGER  int or java.lang.Integer  BIGINT  long or java.lang.Long  SMALLINT  short o ...

  6. java获取数据库的所有列名和对应的数据库类型

    /**     * 连接数据库     * @param driver 数据库的驱动类     * @param url 数据库的地址     * @param userName 数据库的用户名   ...

  7. qt学习笔记(七)之数据库简介(所有支持数据库类型的列表)

    笔者最近用Qt写公司的考勤机.本来要求是要基于frameBuffer下用自己开发的easyGUI来进行上层应用开发,但是考虑到easyGUI提供的接口不是很多,就考虑用Qt来开发,顺带练练手. 废话不 ...

  8. Spring MVC动态切换数据源(多数据库类型)

    最近由于项目需求,需要将Sql Server 和 Mysql 两种数据库整合到一个项目,项目的用到的框架是SSM. 因此尝试了利用AOP切面来切每次执行的Servcie方法,根据Service所在的包 ...

  9. Confluence 6 针对你的数据库类型确定校验 SQL

    不同的数据库通常要求不同的 SQL 校验查询.校验查询通常需要尽可能的简单,这个查询在链接从数据库连接池中取出的时候都会被执行一次. 针对不同的数据库类型,我们推荐先的校验查询 SQL: MySQL ...

随机推荐

  1. Centos7开启ssh免密码登录

    1.输入命令:cd .ssh进入rsa公钥私钥目录(清空旧秘钥) 2.在当前目录下执行ssh-keygen -t rsa,三次回车后生成新的公钥(id_rsa.pub)私钥(id_rsa)文件(每个节 ...

  2. spring4笔记----PropertyPlaceholderConfigurer 属性占位符配置器

    driverClassName=com.mysql.jdbc.Driver url=jdbc:mysql://localhost:3306/spring username=root password= ...

  3. [20181219]script使用小技巧.txt

    [20181219]script使用小技巧.txt --//前几天在使用strace时遇到问题,它的输出使用标准错误句柄.--//我在想平时使用sqlplus如果输出字段很多,屏幕看起来一片混乱.-- ...

  4. c/c++ 数组和指针

    c/c++ 数组和指针 知识点 1,数组就是指针,对应代码里的test1 2,用auto声明,得到的是指针,对应代码里的test2 3,用decltype声明,得到的不是指针 ,对应代码里的test3 ...

  5. Windows Server 2016-Win Ser 2016新增功能

    本来想着整个系列都是与Active Directory相关的内容,上一章节我们应读者要求补充了Window Server 2016标准版与数据中心版的区别,鉴于读者的疑惑,从本章节开始补充三到五章与W ...

  6. 爬楼梯的golang实现

    假设你正在爬楼梯.需要 n 阶你才能到达楼顶. 每次你可以爬 1 或 2 个台阶.你有多少种不同的方法可以爬到楼顶呢? 注意:给定 n 是一个正整数. 输入: 输出: 解释: 有两种方法可以爬到楼顶. ...

  7. 【shell脚本】shell脚本实现的 函数差集查找

    文本地址 点击关注微信公众号 wenyuqinghuai 分享提纲: 1. 问题背景 2. 代码实现 1.问题背景 在做公司的测试的自动化测试时,覆盖了一些开发代码的函数,但是那些还没有做,使用一个函 ...

  8. python 反射、md5加密

    一.issubclass,type,isinstance 1.issubclass :判断xx类是否是yyy类型(包括子类),用于类之间的判定 class GrandF: pass class Fat ...

  9. JavaScript 概述

    什么是JavaScriptJavaScript 是一种具有面向对象能力的.解释型的程序设计语言. 它是基于对象和事件驱动并具有相对安全性的客户端脚本语言. 主要目的是,验证发往服务器端的数据.增加 W ...

  10. 【COCOS2DX-游戏开发之三一】之 坐标系(下) convertToNodeSpace和convertToWorldSpace

    游戏中常常会用到一些变换: 游戏中武器和角色在一个layer上,为了效率.会考虑将bullet, effect和 PhysicsParticle分别放到不用的层上,相应的层上使用batchnode来提 ...