在很多應用系統裡面,雖然一般采用一種數據庫運行,但是由於各種情況的需要,可能業務系統會部署在不同類型的數據庫上,如果開發的系統能夠很方便支持多種數據庫的切換,那可以為我們減少很多煩惱,同時提高系統的適應性和強壯型。還有一種情況,由於業務數據庫的不斷膨脹或者方便數據庫的切割隔離,有時候也會把不同的業務數據庫進行分拆,如權限提供數據庫,客戶關系管理數據庫,工作流程數據庫,企業營運數據庫等等,因此在一個系統裡面,同時使用2個或者以上的數據庫的情況也是有的。
在我較早期的一篇隨筆《Winform開發框架中實現多種數據庫類型切換以及分拆數據庫的支持》裡面,介紹了框架如何在一個項目裡支持多個數據庫的拆分處理。一般情況下,我們都是在一個數據庫類型的情況下,分拆多個數據庫,但是也有變態的需求例外,如我們可能把一些常規的數據庫存儲在本地SQLite數據庫裡面,其他的一些數據放在局域網其他類型數據庫(如SQLServer)裡面;那麼這種同一時刻支持多種數據庫類型,並且給用戶創建BLL層類的時候,動態指定數據庫是否可以實現的呢?
當然可以,我們在上面的基礎上稍微調整一下創建方法即可。
之前介紹了,需要分拆數據庫的話,我們需要在數據訪問基類AbstractBaseDAL裡面,添加一個SetConfigName的方法,用來指定具體的數據庫配置項目,如下所示。
/// <summary> /// 數據訪問層的超級基類,所有數據庫的數據訪問基類都繼承自這個超級基類,包括Oracle、SqlServer、Sqlite、MySql、Access等 /// </summary> public abstract class AbstractBaseDAL<T> where T : BaseEntity, new() { /// <summary> /// 設置數據庫配置項名稱 /// </summary> /// <param name="dbConfigName">數據庫配置項名稱</param> public virtual void SetDbConfigName(string dbConfigName) { this.dbConfigName = dbConfigName; } .................... }
那麼我們這次只需要在這個基礎上調整一下就可以實現同一時刻變換不同數據庫支持的了,由於在框架裡面,我們一般已經實現了多種數據庫訪問的邏輯(如下所示),因此切換起來訪問肯定也是沒問題的(保證有數據庫即可)。
方法就是在BLL層裡面添加一個公開方法,可以設置配置項和數據庫類型的函數,如下所示。
/// <summary> /// 根據參數信息,重新初始化數據訪問層(例:可以指定不同的數據訪問層) /// </summary> /// <param name="dbConfigName">數據庫配置項名稱</param> /// <param name="componentDbType">數據庫類型,默認從ComponentDbType中讀取,如果dbConfigName指定不同類型的數據庫連接,需要指定componentDbType。</param> public void SetConfigName(string dbConfigName, string componentDbType = null) { //componentDbType = null時,從配置項取ComponentDbType的值 string dbType = componentDbType; if (string.IsNullOrEmpty(componentDbType)) { AppConfig config = new AppConfig(); dbType = config.AppConfigGet("ComponentDbType"); } string DALPrefix = GetDALPrefix(dbType); this.dalName = bllFullName.Replace(bllPrefix, DALPrefix);//替換中級的BLL.為DAL.,就是DAL類的全名 baseDal = Reflect<IBaseDAL<T>>.Create(this.dalName, dalAssemblyName);//構造對應的DAL數據訪問層的對象類 if (!string.IsNullOrEmpty(dbConfigName)) { baseDal.SetDbConfigName(dbConfigName); //設置數據庫配置項名稱 } }
這樣我們除了可以設置EnterpriseLibrary的配置項外,還可以指定這個數據庫的類型,不需要全部使用統一的ComponentDbType的值。
如下代碼處理,我們就可以在訪問其他數據庫的時候,切換這個BLL層的對象為其他類型的數據庫(SQLite),這樣不管其他類如何變化,這個Province的數據訪問的是SQLite數據庫裡面的數據。
BLLFactory<Province>.Instance.SetConfig("sqlite", "sqlite");
有時候,我們在一個比較小的應用程序裡面,想靈活對數據庫表進行一些簡單的處理操作,不想使用代碼生成工具生成整個架構的代碼,那麼這個時候,這個CommonDAL就派上用場了,這個可以快速訪問數據庫的表,它的定義如下所示。
這個類的幾個構造函數如下所示,參數分別為表名,主鍵字段,數據庫類型。
/// <summary> /// 默認構造函數 /// </summary> public CommonDAL() { } /// <summary> /// 指定表名以及主鍵,對基類進構造 /// </summary> /// <param name="tableName">表名</param> /// <param name="primaryKey">表主鍵</param> /// <param name="dbType">數據庫類型,如果為空從配置文件裡面獲取ComponentDbType的鍵值</param> public CommonDAL(string tableName) : this(tableName, null, null) { } /// <summary> /// 指定表名以及主鍵,對基類進構造 /// </summary> /// <param name="tableName">表名</param> /// <param name="primaryKey">表主鍵</param> /// <param name="dbType">數據庫類型,如果為空從配置文件裡面獲取ComponentDbType的鍵值</param> public CommonDAL(string tableName, string primaryKey, string dbType = null) : this() { }
這個就是一個精簡版本的AbstractBaseDAL基類,提供了我們能夠使用的多數數據庫操作方法。
例如我在一個驗證視圖及其格式的例子程序裡面,就使用了這個類來實現快速的數據庫操作處理。
/// <summary> /// 判斷視圖名稱是否存在的任務 /// </summary> public class ViewNameExistJob : IExecuteJob { public bool Execute() { List<string> list = DataHelper.GetViewList(); bool allSuccess = true; foreach (string view in list) { CommonDb dal = new CommonDb(view, "F_Guid"); try { DataTable dt = dal.GetReaderSchema(view); } catch (Exception ex) { allSuccess = false; LogTextHelper.Error(string.Format("視圖:{0}不存在。{1}", view, ex.Message)); } } if (allSuccess) { LogTextHelper.Info("視圖全部存在。"); } return allSuccess; } }
或者其他數據庫訪問處理。
CommonDb dal = new CommonDb(view, "F_Guid"); try { int count = dal.GetRecordCount(); if (count == 0) { LogTextHelper.Info(string.Format("視圖【{0}】數據為空,請檢查!", view)); allSuccess = false; } } catch (Exception ex) { allSuccess = false; LogTextHelper.Error(string.Format("視圖:【{0}】不存在。{1}", view, ex.Message)); }
這樣也可以實現多數據庫的隨便切換,不過這個是用於簡易的數據庫訪問,對於需要多種業務封裝的處理類,我們還是使用常規的框架分層模式來實現數據的處理操作。