在很多應(yīng)用系統(tǒng)里面,雖然一般采用一種數(shù)據(jù)庫運(yùn)行,但是由于各種情況的需要,可能業(yè)務(wù)系統(tǒng)會部署在不同類型的數(shù)據(jù)庫上,如果開發(fā)的系統(tǒng)能夠很方便支持多種數(shù)據(jù)庫的切換,那可以為我們減少很多煩惱,同時提高系統(tǒng)的適應(yīng)性和強(qiáng)壯型。還有一種情況,由于業(yè)務(wù)數(shù)據(jù)庫的不斷膨脹或者方便數(shù)據(jù)庫的切割隔離,有時候也會把不同的業(yè)務(wù)數(shù)據(jù)庫進(jìn)行分拆,如權(quán)限提供數(shù)據(jù)庫,客戶關(guān)系管理數(shù)據(jù)庫,工作流程數(shù)據(jù)庫,企業(yè)營運(yùn)數(shù)據(jù)庫等等,因此在一個系統(tǒng)里面,同時使用2個或者以上的數(shù)據(jù)庫的情況也是有的。
在我較早期的一篇隨筆《Winform開發(fā)框架中實(shí)現(xiàn)多種數(shù)據(jù)庫類型切換以及分拆數(shù)據(jù)庫的支持》里面,介紹了框架如何在一個項(xiàng)目里支持多個數(shù)據(jù)庫的拆分處理。一般情況下,我們都是在一個數(shù)據(jù)庫類型的情況下,分拆多個數(shù)據(jù)庫,但是也有變態(tài)的需求例外,如我們可能把一些常規(guī)的數(shù)據(jù)庫存儲在本地SQLite數(shù)據(jù)庫里面,其他的一些數(shù)據(jù)放在局域網(wǎng)其他類型數(shù)據(jù)庫(如SQLServer)里面;那么這種同一時刻支持多種數(shù)據(jù)庫類型,并且給用戶創(chuàng)建BLL層類的時候,動態(tài)指定數(shù)據(jù)庫是否可以實(shí)現(xiàn)的呢?
當(dāng)然可以,我們在上面的基礎(chǔ)上稍微調(diào)整一下創(chuàng)建方法即可。
之前介紹了,需要分拆數(shù)據(jù)庫的話,我們需要在數(shù)據(jù)訪問基類AbstractBaseDAL里面,添加一個SetConfigName的方法,用來指定具體的數(shù)據(jù)庫配置項(xiàng)目,如下所示。
/// <summary> /// 數(shù)據(jù)訪問層的超級基類,所有數(shù)據(jù)庫的數(shù)據(jù)訪問基類都繼承自這個超級基類,包括Oracle、SqlServer、Sqlite、MySQL、access等 /// </summary> public abstract class AbstractBaseDAL<T> where T : BaseEntity, new() { /// <summary> /// 設(shè)置數(shù)據(jù)庫配置項(xiàng)名稱 /// </summary> /// <param name="dbConfigName">數(shù)據(jù)庫配置項(xiàng)名稱</param> public virtual void SetDbConfigName(string dbConfigName) { this.dbConfigName = dbConfigName; } ....................}
那么我們這次只需要在這個基礎(chǔ)上調(diào)整一下就可以實(shí)現(xiàn)同一時刻變換不同數(shù)據(jù)庫支持的了,由于在框架里面,我們一般已經(jīng)實(shí)現(xiàn)了多種數(shù)據(jù)庫訪問的邏輯(如下所示),因此切換起來訪問肯定也是沒問題的(保證有數(shù)據(jù)庫即可)。

方法就是在BLL層里面添加一個公開方法,可以設(shè)置配置項(xiàng)和數(shù)據(jù)庫類型的函數(shù),如下所示。
/// <summary> /// 根據(jù)參數(shù)信息,重新初始化數(shù)據(jù)訪問層(例:可以指定不同的數(shù)據(jù)訪問層) /// </summary> /// <param name="dbConfigName">數(shù)據(jù)庫配置項(xiàng)名稱</param> /// <param name="componentDbType">數(shù)據(jù)庫類型,默認(rèn)從ComponentDbType中讀取,如果dbConfigName指定不同類型的數(shù)據(jù)庫連接,需要指定componentDbType。</param> public void SetConfigName(string dbConfigName, string componentDbType = null) { //componentDbType = null時,從配置項(xiàng)取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);//構(gòu)造對應(yīng)的DAL數(shù)據(jù)訪問層的對象類 if (!string.IsNullOrEmpty(dbConfigName)) { baseDal.SetDbConfigName(dbConfigName); //設(shè)置數(shù)據(jù)庫配置項(xiàng)名稱 } }這樣我們除了可以設(shè)置EnterpriseLibrary的配置項(xiàng)外,還可以指定這個數(shù)據(jù)庫的類型,不需要全部使用統(tǒng)一的ComponentDbType的值。
如下代碼處理,我們就可以在訪問其他數(shù)據(jù)庫的時候,切換這個BLL層的對象為其他類型的數(shù)據(jù)庫(SQLite),這樣不管其他類如何變化,這個Province的數(shù)據(jù)訪問的是SQLite數(shù)據(jù)庫里面的數(shù)據(jù)。
BLLFactory<Province>.Instance.SetConfig("sqlite", "sqlite");有時候,我們在一個比較小的應(yīng)用程序里面,想靈活對數(shù)據(jù)庫表進(jìn)行一些簡單的處理操作,不想使用代碼生成工具生成整個架構(gòu)的代碼,那么這個時候,這個CommonDAL就派上用場了,這個可以快速訪問數(shù)據(jù)庫的表,它的定義如下所示。

這個類的幾個構(gòu)造函數(shù)如下所示,參數(shù)分別為表名,主鍵字段,數(shù)據(jù)庫類型。
/// <summary> /// 默認(rèn)構(gòu)造函數(shù) /// </summary> public CommonDAL() { } /// <summary> /// 指定表名以及主鍵,對基類進(jìn)構(gòu)造 /// </summary> /// <param name="tableName">表名</param> /// <param name="primaryKey">表主鍵</param> /// <param name="dbType">數(shù)據(jù)庫類型,如果為空從配置文件里面獲取ComponentDbType的鍵值</param> public CommonDAL(string tableName) : this(tableName, null, null) { } /// <summary> /// 指定表名以及主鍵,對基類進(jìn)構(gòu)造 /// </summary> /// <param name="tableName">表名</param> /// <param name="primaryKey">表主鍵</param> /// <param name="dbType">數(shù)據(jù)庫類型,如果為空從配置文件里面獲取ComponentDbType的鍵值</param> public CommonDAL(string tableName, string primaryKey, string dbType = null) : this() { }這個就是一個精簡版本的AbstractBaseDAL基類,提供了我們能夠使用的多數(shù)數(shù)據(jù)庫操作方法。
例如我在一個驗(yàn)證視圖及其格式的例子程序里面,就使用了這個類來實(shí)現(xiàn)快速的數(shù)據(jù)庫操作處理。
/// <summary> /// 判斷視圖名稱是否存在的任務(wù) /// </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; } }或者其他數(shù)據(jù)庫訪問處理。
CommonDb dal = new CommonDb(view, "F_Guid"); try { int count = dal.GetRecordCount(); if (count == 0) { LogTextHelper.Info(string.Format("視圖【{0}】數(shù)據(jù)為空,請檢查!", view)); allSuccess = false; } } catch (Exception ex) { allSuccess = false; LogTextHelper.Error(string.Format("視圖:【{0}】不存在。{1}", view, ex.Message)); }這樣也可以實(shí)現(xiàn)多數(shù)據(jù)庫的隨便切換,不過這個是用于簡易的數(shù)據(jù)庫訪問,對于需要多種業(yè)務(wù)封裝的處理類,我們還是使用常規(guī)的框架分層模式來實(shí)現(xiàn)數(shù)據(jù)的處理操作。
新聞熱點(diǎn)
疑難解答
圖片精選