本文從構建一個簡單的工廠模式建立適合的數據提供程序(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);
雖然提供程序的工廠模式能讓咱們訪問不一樣的數據庫,可是這種模式,一樣也限制了咱們對特定數據庫訪問的靈活性,由於該模式站在一個更好的抽象層次上,着重點在通用,適合全部的數據提供對象,雖然,可使用類型轉換,可是所以會增長許多運行時的檢測來保證轉換不會拋出異常。本文只是一個基礎的使用介紹,在此基礎上,你能夠構建一個完整的通用數據訪問層。