本文从构建一个简单的工厂模式建立适合的数据提供程序(DataProvider)开始,到使用 ADO.NET 为咱们提供的DbProviderFactories 来建立一个适合的数据提供程序结束。并补充了去除简化工厂模式中的 case 语句,使用反射的方式简化工厂模式。html
首先,假设咱们要提供访问如下数据库,如:Sqlserver、MySQL、Oracle、OleDb、… 。mysql
接着,咱们能够定义一个方法根据传入参数的不一样,建立不一样的链接对象。sql
private static IDbConnection GetConnection(string provider) { IDbConnection conn = null; switch (provider) { case "SqlServer": conn = new SqlConnection(); break; case "MySQL": // 须要添加程序集:mysql.data.dll // 并引用命名空间 MySql.Data.MySqlClient conn = new MySqlConnection(); break; case "Oracle": // 须要引用程序集:System.Data.OracleClient.dll // 并引用命名空间 System.Data.OracleClient conn = new OracleConnection(); break; case "OleDb": conn = new OleDbConnection(); break; } return conn; }
既然 case 中固定的这几个链接对象,何不改成枚举值呢?数据库
下面定义了一个枚举类型:缓存
/// <summary> /// 数据提供程序枚举 /// </summary> enum DataProviderEnum { SqlServer, MySQL, Oracle, OleDb, None }
接着,更改上面的GetConnection():app
/// <summary> /// 根据传入枚举值,建立对应的数据库链接对象 /// </summary> private static IDbConnection GetConnection(DataProviderEnum provider) { IDbConnection conn; switch (provider) { case DataProviderEnum.SqlServer: conn = new SqlConnection(); break; case DataProviderEnum.MySQL: // 须要添加程序集:mysql.data.dll // 并引用命名空间 MySql.Data.MySqlClient conn = new MySqlConnection(); break; case DataProviderEnum.Oracle: // 须要引用程序集:System.Data.OracleClient.dll // 并引用命名空间 System.Data.OracleClient conn = new OracleConnection(); break; case DataProviderEnum.OleDb: conn = new OleDbConnection(); break; } return conn; }
下面来验证一下,咱们上面的代码是否可以正确执行:ide
static void Main() { Console.WriteLine("Simple Connection Factory.\n"); IDbConnection conn = GetConnection(DataProviderEnum.MySQL); if (conn == null) { throw new NullReferenceException("conn is not allow null!"); } Console.WriteLine(conn.GetType().FullName); Console.Read(); }
执行结果以下图:spa
可见,咱们的程序可以正确执行。code
Note: MySQL 程序集下载地址: http://dev.mysql.com/downloads/connector/net/5.2.htmlserver
Microsoft 为咱们提供了一个 DbProviderFactories 类,该类有一个静态方法 GetFactory(), 可以得到指定的数据提供程序的 DbProviderFactory。
Note: DbProviderFactories 类型只能从获取有效的数据提供程序列表中获取相应的 DbProviderFactory。有效的数据提供程序列表记录在machine.config 文件的 <DbProviderFactory> 节点内。(C:\Windows\Microsoft.NET\Framework\v2.0.50727\CONFIG\machine.config)
<system.data> <DbProviderFactories> <add name="Odbc Data Provider" invariant="System.Data.Odbc" description=".Net Fram <add name="OleDb Data Provider" invariant="System.Data.OleDb" description=".Net Fr <add name="OracleClient Data Provider" invariant="System.Data.OracleClient" descri <add name="SqlClient Data Provider" invariant="System.Data.SqlClient" description= </DbProviderFactories> </system.data>
上面代码中的 invariant 的值既是 GetFactory() 所需的参数。
这里,没有 MySQL 的数据提供程序,咱们能够增长新的不变值指向GAC(全局程序集缓存),路径:C:\Windows\assembly\。关于这个话题,能够参考程序集相关章节,这里不作介绍。
你也能够经过代码来查看所支持的提供程序列表:
// 获取支持的数据提供程序 public void PrintProviderTalbe() { DataTable table = DbProviderFactories.GetFactoryClasses(); for (int i = 0; i < table.Rows.Count; i++) { Console.WriteLine("{0}", table.Rows[i][0]); } }
public static void ExecuteNonQuery(string cmdText) { string providerName = "System.Data.SqlClient"; string connStr = "Data Source=.; Integrated Security=SSPI; Initial Catalog=DataBaseName"; // 获取提供程序 DbProviderFactory provider = DbProviderFactories.GetFactory(providerName); // 建立链接对象 DbConnection connection = provider.CreateConnection(); connection.ConnectionString = connStr; connection.Open(); // 建立命令对象 DbCommand command = provider.CreateCommand(); command.CommandText = cmdText; command.Connection = connection; command.ExecuteNonQuery(); }
上面的方法实现了完整的获取提供程序对象,建立链接对象和命令对象的方式。一般状况下,咱们会把 providerName 和 connStr 放到配置文件中,从配置文件中获取,这样就不用每次从新编译程序集。
下面咱们来改下这个方法:
string providerName = ConfigurationManager.AppSettings["SqlProvider"]; string connStr = ConfigurationManager.ConnectionStrings["SqlConnStr"];
Note:使用 ConfigurationManager 须要引用 System.Configuration.dll
Config 文件以下:
<appSettings> <add key="SqlProvider" value="System.Data.SqlClient"/> <add key="OleDbProvider" value="System.Data.OleDb"/> </appSettings> <!--Here are the connection strings--> <connectionStrings> <add name="SqlConnStr" connectionString="Data Source=.; Initial Catalog=DataBaseName; Integrated Security=SSPI"/> <add name="OleDbConnStr" connectionString="Provider=SQLOLEDB; Data Source=.; Initial Catalog=DataBaseName; Integrated Security=SSPI"/> </connectionStrings>
注意:<appSettings> 与 <connectionStrings> 这两个的不一样之处,能够这么理解,<connectionStrings> 是专门用来提供配置链接字符串的,而 <appSettings> 以键值对的方式为应用程序提供额外的配置。
使用反射的方式简化简单工厂中的 Switch(),将代码改成以下:
/// <summary> /// 使用反射获取数据库链接对象 /// </summary> /// <param name="assemblyName">程序集名称</param> /// <param name="providerFullName">类型完整名称</param> /// <returns>合适的数据库链接对象</returns> private static IDbConnection GetConnection(string assemblyName, string providerFullName) { IDbConnection conn = null; conn = (IDbConnection)Assembly.Load(assemblyName).CreateInstance(providerFullName); return conn; }
Main() 方法中代码以下:
IDbConnection conn = GetConnection("mysql.data", "MySql.Data.MySqlClient.MySqlConnection"); Console.WriteLine(conn.GetType().FullName);
虽然提供程序的工厂模式能让咱们访问不一样的数据库,可是这种模式,一样也限制了咱们对特定数据库访问的灵活性,由于该模式站在一个更好的抽象层次上,着重点在通用,适合全部的数据提供对象,虽然,可使用类型转换,可是所以会增长许多运行时的检测来保证转换不会抛出异常。本文只是一个基础的使用介绍,在此基础上,你能够构建一个完整的通用数据访问层。