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


一、在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. 计算机图形学(第2版 于万波 于硕 编著)第45页的Bresenham算法有错误

    计算机图形学(第2版 于万波 于硕 编著)第45页的Bresenham算法有错误: 书上本来要写的是以x为阶越步长的方法,但是他写的是用一部分y为阶越步长的方法(其实也写的不对),最后以x为阶越步长的 ...

  2. C#核心基础--静态类&部分类

    静态类 用 static 关键字修饰的类叫做静态类,静态类通常用来定义工具类.静态类不能实例化,不能从指定基类继承而来,静态类隐式从 Object 类继承而来.静态类只能包含静态成员和常量,因为常量是 ...

  3. ASP.NET Core 1.0、ASP.NET MVC Core 1.0和Entity Framework Core 1.0

    ASP.NET 5.0 将改名为 ASP.NET Core 1.0 ASP.NET MVC 6  将改名为 ASP.NET MVC Core 1.0 Entity Framework 7.0    将 ...

  4. SQL Server 锁机制

    锁兼容性图: 一.锁的粒度: 比较需要注意的是RID/KEY.HoBT/PAGE这两对儿的区别,RID和HoBT是针对堆表的,即没有聚集索引的表. 二.锁的模式: 1.关于其中的S.U.X锁: 共享锁 ...

  5. Linux CPU占用率监控工具小结

    关键词:top.perf.sar.ksar.mpstat.uptime.vmstat.pidstat.time.cpustat.munin.htop.glances.atop.nmon.pcp-gui ...

  6. Linux用户抢占和内核抢占详解(概念, 实现和触发时机)--Linux进程的管理与调度(二十)

    1 非抢占式和可抢占式内核 为了简化问题,我使用嵌入式实时系统uC/OS作为例子 首先要指出的是,uC/OS只有内核态,没有用户态,这和Linux不一样 多任务系统中, 内核负责管理各个任务, 或者说 ...

  7. 5. svg学习笔记-坐标系变换

    之前我们编写图形元素的时候,编写好了位置大小就是固定的,通过坐标系变换,可以移动缩放,旋转图形,但必须声明的是,进行变换时是图形相对于坐标系的变化,就是图形是不发生变化的,而是坐标系发生了变化,比如缩 ...

  8. LeetCode算法题-Intersection of Two Arrays II(Java实现)

    这是悦乐书的第208次更新,第220篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第76题(顺位题号是350).给定两个数组,编写一个函数来计算它们的交集.例如: 输入: ...

  9. FCM算法的matlab程序2

    FCM算法的matlab程序2 在“FCM算法的matlab程序”这篇文章中已经用matlab程序对iris数据库进行实现,并求解准确度.下面的程序是另一种方法,是最常用的方法:先初始化聚类中心,在进 ...

  10. 谱聚类算法(Spectral Clustering)

        谱聚类(Spectral Clustering, SC)是一种基于图论的聚类方法--将带权无向图划分为两个或两个以上的最优子图,使子图内部尽量相似,而子图间距离尽量距离较远,以达到常见的聚类的 ...