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


一、在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. Android智能指针SP WP使用方法介绍

    Android手机操作系统既然是开源的操作系统.那么在具体的文件夹中就会存放着各种相关功能的开源代码.我们在使用的时候可以根据这些源代码进行相应的修改就能轻松的完成我们所需的功能.在这里大家就一起来看 ...

  2. linux:644、755、777权限详解

    第一位7等于4+2+1,rwx,所有者具有读取.写入.执行权限: 第二位5等于4+1+0,r-x,同组用户具有读取.执行权限但没有写入权限: 第三位5,同上,也是r-x,其他用户具有读取.执行权限但没 ...

  3. MySQL open_tables和opened_tables

    官网解释参见:https://dev.mysql.com/doc/refman/5.7/en/table-cache.html 其他可供参考的文章有: 关于表限制参数的使用:https://dba.s ...

  4. c/c++ 标准库 map set 大锅炖

    标准库 map set 大锅炖 一,关联容器有哪些 按关键字有序保存元素 map 保存key和value set 只保存key mulutimap key可以重复出现 multiset key可以重复 ...

  5. python设计模式之单例模式(转)

    设计模式之单例模式 单例设计模式是怎么来的?在面向对象的程序设计中,当业务并发量非常大时,那么就会出现重复创建相同的对象,每创建一个对象就会开辟一块内存空间,而这些对象其实是一模一样的,那么有没有办法 ...

  6. February 25th, 2018 Week 9th Sunday

    LIfe is about making an impact, not making an income. 生命在于影响他人,而非赚钱糊口. From Kevin Kruse. You probabl ...

  7. Ubuntu 12.04上安装MySQL并运行

    Ubuntu 12.04上安装MySQL并运行 作者:凯鲁嘎吉 - 博客园 http://www.cnblogs.com/kailugaji/ 安装MySQL数据库 sudo apt-get upda ...

  8. c#基础知识之 Dataset 索引0没有值

    datatable绑定到dataGrieView,在刷新datatable的数据时,常会bug:索引0没有值或索引(int)x没有值 昨天弄了一个下午,发现bug原因: dataGridView中有数 ...

  9. huapin

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  10. (转)Spring Boot (十三): Spring Boot 小技巧

    http://www.ityouknow.com/springboot/2017/06/22/spring-boot-tips.html 一些 Spring Boot 小技巧.小知识点 初始化数据 我 ...