程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> 走進Linq-Linq to SQL源代碼賞析之Provider的初始化

走進Linq-Linq to SQL源代碼賞析之Provider的初始化

編輯:關於.NET

話說Linq to SQL理論上應該支持多種數據庫的,而且應該支持多種數據庫, 到最後卻落的這個局面,是為了商業考慮還是本來技術就不成熟?不得而知。不 過不管怎麼說Linq to SQL的體系結構確實是支持擴展的。

在 System.Data.Linq.Mapping這個命名空間下微軟提供了一個特性: ProviderAttribute,使用強類型的DataContext或使用Xml做映射的時候,該特 性可以用來指定具體的數據庫提供者。如下:

[Database(“dbo.cnblogs”)]
[Provider(typeof(SqlProvider))]
Public CnBlogDataContext : DataContext
{

}

這就 表明我們的Linq to SQL是基於Sql Server數據庫了,SqlProvider是實現了 IProvider接口的(該接口存在於System.Data.Linq.Provider命名空間下)。

在DataContext初始化時執行的Init方法裡有這樣幾行代碼:

if (model.ProviderType == null)
{
throw Error.ProviderTypeNull();
}
Type providerType = model.ProviderType;
if (!typeof(IProvider).IsAssignableFrom(providerType))
{
throw Error.ProviderDoesNotImplementRequiredInterface(providerType,
typeof(IProvider));
}
this.provider = (IProvider) Activator.CreateInstance(providerType);
this.provider.Initialize(this.services, connection);

這裡是根據model的ProviderType 創建一個IProvider的實例。Model就是一個MetaModel對象。前面兩篇都提到了 MetaModel有兩個子類,AttributeMetaModel和XmlMetaModel,看看你是用哪種 方法做映射的,我們這裡就用AttributeMetaModel做例子,在 AttributeMetaModel的構造函數裡有這樣幾行代碼:

ProviderAttribute[] customAttributes = (ProviderAttribute[]) this.contextType.
GetCustomAttributes(typeof(ProviderAttribute), true);
if ((customAttributes != null) && (customAttributes.Length == 1))
{
this.providerType = customAttributes[0].Type;
}
else
{
this.providerType = typeof(SqlProvider);
}

從DataContext類上找Provider 特性,如果沒有找到就默認使用SqlProvider了。創建了IProvider的實例就會調 用它的Initialize方法進行初始化。Initialize方法需要兩個參數IDataService 和一個連接對象(DbConnection或是連接字符串)。

關於設計模式的旁 白

橋接模式

看到這裡也許大家都說,哦,原來實際的事情都是這 個IProvider干的啊,IProvide是個接口,下面可能有SqlProvider, OracleProvider,AccessProvider,只要提供這些Provider我們就可以無限擴展 數據庫了。是的,設計到這一步已經可以滿足多數據庫的要求了,但是數據庫種 類的多樣性只是一個方面,還有每種數據庫版本的差異呢?如果我們就使用繼承 ,就這樣無限的去擴展,最後會得到一個很復雜的類層次,層次搞復雜後不僅僅 難於重構,更要的是會出現很多重復,靈活性也降低了。

如果光使用繼 承,我們可能會得到這樣的繼承樹:

這樣的繼承層次看起來貌似很“專業”,但是靈活性實在 是不敢恭維,首先,任何一個層次的小小變動在整個繼承鏈上都要改動,如果增 加一種數據庫,而這種數據有會有幾種版本,各個版本之間又有些差異,那麼類 的數量會成倍增長。還有一個,那就是子類之間有可能造成重復,假如 Sql2000Provider和Oracle9iProvider之間有重復怎麼辦?C#又不支持多繼承, 我們無法使用Martin Folwer的重構方法將子類重復的部分提升到父類。那有什 麼好辦法呢?看看微軟的設計師是怎麼干的。

IProvder的初始化方法 Initialize需要兩個參數,其中一個就是一個IDataService接口(注意,這裡是 接口,那肯定有很多實現,不過由於Linq to SQL就支持一種數據庫,現在也只 有一種實現了,不過我們可以通過這種形式來想象和擴展,並可以學習這種理念 ),這個時候我們得到的是另外一種類圖:

這裡以組合的方式,組合Provider和IDataService,類的繼承層次簡 明了很多,也可以很容易處理子類之間的重復了。

實際上這就是橋接模 式,該模式的意圖是抽象和實現相分離,在這裡IProvider就是抽象,而 IDataService這邊就是實現了。通過IDataService這個接口,把SqlProvider和 CommonDataService,DBProvider和DBDataService之間的依賴消除了。仔細體會 一下,我們的實際項目中在哪些地方出現過這樣的場景?不久以前我發了一篇博 客《重構到Brdge模式》,那裡描述了我實際項目中一個真實的場景。

請 注意的是,實際的Linq to SQL因為只支持SQL Server,所以上面的類圖描述的 關系並不存在,但是我們從代碼中完全可以想象的到即使要擴展也是很容易的, 這就是架構的力量,即使是昨天的設計也能應付明天的變化。

關於 Provider的初始化就介紹到這裡了,在文章末尾的源代碼下載裡提供了 IProvider類和SqlProvider類,你可以看看初始化的過程,並聯系上面的圖想想 如何構建一個可擴展的架構。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved