切出Data Layout,通常是一個資料庫應用程式最初、也是最重要的部分,或許有些初學者對此感到困惑,是的!你可以用SqlDataSource做出客戶資料的編修畫面,
但一旦牽扯到商業邏輯,SqlDataSource絕對不會是選項,硬要使用的話會成為負擔。
想像一下,當設計訂單編修畫面時,你可以使用SqlDataSource來呈現訂單表頭及表身的編輯動作,但儲存前後庫存的控管就一定得回到ADO.NET處理,這時商業
邏輯便會呈現出與UI混雜的窘境,整個應用程式也會變得難以維護。
The Framework Designing (4) – Abstract Data Layout
文/黃忠成
a simple application
切出Data Layout,通常是一個資料庫應用程式最初、也是最重要的部分,或許有些初學者對此感到困惑,是的!你可以用SqlDataSource做出客戶資料的編修畫面,
但一旦牽扯到商業邏輯,SqlDataSource絕對不會是選項,硬要使用的話會成為負擔。
想像一下,當設計訂單編修畫面時,你可以使用SqlDataSource來呈現訂單表頭及表身的編輯動作,但儲存前後庫存的控管就一定得回到ADO.NET處理,這時商業
邏輯便會呈現出與UI混雜的窘境,整個應用程式也會變得難以維護。
切出Data Layout最初的動機,通常也就是分割資料存取、商業邏輯與UI,其它的如可抽換的商業邏輯或是可抽換的Data Layout就只是更深一層的考量而已。
就架構上而言,不管是ASP.NET或WinForm、WPF,都應該要將應用程式設計成如圖1的基礎架構,也就是切出一個DataModel專門處理資料存取及商業邏輯的部分。
圖1
具現於ASP.NET專案的樣子就像圖2。
圖2
這個範例(Step1目錄)中將DataSet/TableAdapters放在另一個Class Library中,然後於WebApplication1專案中以ObjectDataSource來結合,這種架構在需要處理訂單與
庫存間的關係時,程式碼會寫在DataModel中,而不是包含UI的WebApplication。
designing database-independent data layout
誠如先前提到的,切出Data Layout的最初目的是隔離UI及資料處理,但接下來的那一步通常就會出現可切換資料庫的需求,這有很多種解決辦法,最簡單的就是乾脆使用
ADO.NET Entity Framework或NHibernate等OR/Mapping Framework。
不過有時我們可能會因為不熟悉這些Framework或是其它原因而捨其不用,改採透過架構設計的方式來達到可切換資料庫的需求,此時通常需要由Data Layout中切出一小塊
Data Access Layout,然後令其成為可抽換的部分,如圖3所示。
圖3
這個範例(Step2)跟前例不同的是,其將TableAdapters部分由DataModel中抽離,成為一個名為SqlDataModel的Class Library,而主應用程式透過app.config的設定來載入,
當資料庫由Sql Server換成Oracle時,只需要撰寫一個OracleDataModel並修改app.config,即可讓整個應用程式由使用Sql Server資料庫變成Oracle。
Default.aspx.cs(in WebApplication1 project) |
|
web.config |
<?xmlversion="1.0"?> <configuration> <system.web> <compilationdebug="true"targetFramework="4.0"/> </system.web> <connectionStrings> …………………. </connectionStrings> <appSettings> <addkey="Customers"value="SqlDataModel.SqlCustomersModel, SqlDataModel"/> </appSettings> </configuration> |
當然,看起來是很簡單,但如果仔細去查看DataModel及SqlDataModel的內容,會發現其必須要定出很多的函式來符合UI存取資料庫的需求,當使用OR/Mapping Framework時,
就可以跳過這些繁瑣的步驟,直接開始撰寫實際的應用程式。另外有一點需特別提出來,那就是在設計Data Access Layout時,不要朝可應用於其他不同系統的角度出發,因為這樣
一來就會設計出類似於ADO.NET Entity Framework的架構,而這個本來就不是我們所預期的結果,而且也沒那麼多時間可以實作這種東西。
make robust contract
前例的缺點是偷懶應用了ObjectDataSource使用Reflection的特點,跳過了定義應用程式與SqlDataModel間的協定,實務上,你絕對會需要自己建立SqlDataModel並呼叫其特定的函式,
例如當搜尋客戶編號時需呼叫SqlDataModel的GetCustomerByID函式,如果採用前例的作法,就只能透過Reflection呼叫了,這是很沒有效率及很危險的手法,定義兩者互通的介面才是
真正的解決之道。
圖4
此範例的原始碼於Step3目錄中,在此也首次看到了此架構的另一個特色,那就是可以讓Web Application/Win Form Application共用一個Data Layout,也就是共用資料層。
from client/server to multi-tier with designed data layout
現今的中大型資料庫應用程式,多半會採用Multi-Tier的系統架構,也就是說將資料存取層放置於Web Service之中,Step4目錄中就是這種架構的範例程式。
圖5
圖5有兩個亮點,一是其將原本直接參考DataModel的部分,改為呼叫WCF Service,也就是說Web Application、WIn Form Application的資料層就是WCF Service,
第二點是Data Service也就是擔任資料層的WCF Service還是沿用動態載入Data Access Layout的部分,其仍然擁有可抽換式Data Access Layout的特色。
dataset or not?
當將應用程式由Client/Server架構移轉為Multi-Tier架構時,最常遭遇的選擇就是是否還要使用DataSet/DataTable,如果UI是ASP.NET/WinForm/WPF的話,那麼
這個問題就不是那麼重要了,因為三者皆能妥善的處理WCF Service間DataSet/DataTable的傳遞,但如果需要提供Silverlight或是與Java Client Application互動時,
DataSet/DataTable先天上複雜的XML結構就會成為阻礙。
這時只能夠選擇解析DataSet/DataTable的XML或是另外定義Data Objects(又稱為Data Transfer Object Pattern)來傳遞,如圖6的架構。
圖6
首先要把Data Objects給定義出來,這應該定義於DataModel Project中。
NorthwindModel.cs |
|
接著要修改ICustomersModel的介面定義。
DataModelIntf.cs |
|
最後實作放置於SqlCustomersModel專案中。
SqlCustomersModelImpl.cs |
|
這樣一來,ASP.NET/Windows Form/Silverlight就能共用此DataService,達到多UI共用單一Service層UI的架構,完整範例於Step6目錄中。
what’s we not say?
一切似乎都很美好不是,不同UI可以共用一個Service層,而Service層的Data Access Layout也是可抽換的,可達到不變UI/Service的情況下將SQL Server改為Oracle,那還有什麼不滿的呢?
有的,那就是當客戶不需要這種Multi-Tier架構, 覺得使用一般的Client/Server架構就可,還可省略掉Service層讓系統達到更高的效率。
其實,我們一開始為Client/Server所設計的架構就能適應這些需求,只要將Data Objects的概念加入,該架構不但可以不換UI的情況下由Client/Server轉變為Multi-Tier,關鍵就在於可抽換的
DataModel層,如圖7所示。
圖7
圖7中,當應用程式是Client/Server架構時,就直接使用SqlDataModel做為DataModel,形成不需要Service層的架構,日後若客戶需要,可以直接把SqlDataModel換成DataServiceModel,
由它來代理與Data Service溝通,這樣就直接變成Multi-Tier了,Step7目錄中是此架構的完整範例。