一 擴展表格適配器 當你設計業務層和數據存取層時
你基本上都是把實體和關系分別映射到數據庫表格及表格列中
典型地
我們期望每個實體的行為是
通過一系列語句來執行數據庫操作
那麼
你該如何描述一個實體的行為呢?數據存取設計模式在這方面提供了一定的指導作用
其實
一個表格適配器的CommandCollection屬性是一個內部數據結構
它提供的語句用於硬編碼在一個表格上期望的行為
因此
如果你想在Customers表格上添加一種行為
那麼
你需要把一個新的T
SQL語句添加到CommandCollection屬性
然後經由CustomersTableAdapter類中的一個新的方法使其成為public型屬性
Visual Studio
提供一個簡單的向導來完成所有這些工作
只要簡單地選擇在表格適配器設計器中定義的一個任務
你就可以觸發這個向導
如圖
所示
圖
選擇表格適配器設計器定義的一個任務觸發特定的向導
當你在Visual Studio
中選擇一個表格適配器組件時
它將顯示一個靈敏標簽
點擊它之後
Visual Studio就會顯示一個菜單
如果你選擇編輯查詢
那麼
你會得到當前數據集組件中所有表格的一個圖形表示(見圖
)
圖
Visual Studio
數據設計器提供的表格關系和表格適配器
要編輯一個現有查詢
你只要選擇表格適配器任務列表中的任務並編輯Properties窗口中的屬性即可
為了添加一個新任務
你可以選擇
Add Query
然後遵循隨後向導的提示即可
該向導最終引導你定義一個新的命令
無論它是一個查詢或是一個更新語句
完成之後
你會看到一個額外的入口出現在任務列表內
另外
對基本代碼也進行了一定程度的修改
現在
假定你定義了一個新的查詢語句—用於根據不同國家加載相應的顧客信息
那麼
最後的語句看起來類似如下
SELECT
FROM customers WHERE country=@country
向導會要求你為使用該語句檢索數據(GetDataXXX)並填充傳遞的數據表格(FillXXX)的兩個方法進行命名
當然
你可以選擇僅生成其中一個方法
讓我們如圖
所示來命名方法GetDataByCountry和FillByCountry
圖
添加到表格適配器的新任務
這兩個新的方法都要使用從命令集合中提取的命令來建立適配器的SelectCommand語句並執行它
列表
展示了該FillByCountry方法的源代碼
列表
FillByCountry方法的源代碼
The new FillByCountry method
Public Overridable Overloads Function FillByCountry( _
ByVal dataTable As CustomersDataTable
_
ByVal country As String) As Integer
Me
Adapter
SelectCommand = Me
CommandCollection(
)
If (country Is Nothing) Then
Me
Adapter
SelectCommand
Parameters(
)
Value = System
DBNull
Value
Else
Me
Adapter
SelectCommand
Parameters(
)
Value = CType(country
String)
End If
If (Me
ClearBeforeFill = True) Then
dataTable
Clear()
End If
Dim returnValue As Integer = Me
Adapter
Fill(dataTable)
Return returnValue
End Function
二 生成代碼評價
值得注意的是圍繞DataSet和BindingSource組件生成的代碼使用了中斷連接模型和普通的TSQL語句這並不是說不管你是通過Visual Studio 向導編輯代碼或是手工編輯都可以毫無顧忌地使用存儲過程和事務
這裡所使用的中斷連接模型要求在表單啟動時所有的數據都必須已經被加載到內存中但是在這種情況下你仍然能夠自由地編輯自動生成的代碼例如使應用程序僅加載它在運行時刻需要的數據默認情況下一個使用Visual Studio 數據設計器生成代碼的數據綁定表單的Load事件看起來如下所示
Sub NorthwindForm_Load(ByVal sender As Object
_
ByVal e As EventArgs) Handles MyBase
Load
CustomersTableAdapter
Fill(nwDataSet
Customers)
//…………
End Sub
Visual Studio 在綁定的DataSet組件內相應於每個表格適配器放入了一個對Fill方法的調用
須知Visual Studio 生成的代碼將同工程的其它部分一起編譯在無法完全滿足你的需要和要求時決不應該相當然地使用這些代碼你可以自由地修改它但是在這樣做之前你首先應該深入理解它的邏輯與結構不要相當然認為一個向導能為你實現一切或者干脆放棄使用之你應該接受它然後修改之以適合你的需要大多數時候這是你必須做的當然也是最明智的選擇
三 DAL通用模式
任何相當復雜的系統都要求實現許多不同層來存取和操作數據比如你可以使用業務邏輯層(BLL)來與用戶接口進行通訊並且提供安全檢查數據校驗以及其它服務例如數據的預處理和事後處理等另一方面你可以使用數據存取層(DAL)來存取和檢索數據其實該DAL僅是一個合並了API功能實現數據庫存取的組件CRUD部分的任務相應於一個DAL部分的目標也即是把數據暴露給業務層以便實現數據交換這些層按特定順序迭放在一起DAL層由BLL層使用並且不應該被用戶接口所利用以免打破各層之間的分離原則
當你想創建一個庫以便合並數據存取功能時你該怎麼辦呢?是否應該使用Visual Studio 數據設計器所提出的定制的基於表格的方法?或是具有較好的條件而使用一個商業性的O/R映射器工具來生成大多數代碼?還是打算自己開發DAL?幸好這些選擇並非互斥的完全可以根據需要進行混合使用於是問題出現了你應該怎麼辦?現在讓我們首先來理解通用模式在這樣做時你還是應該首先搞清楚Visual Studio 所提供的方法和邏輯
一般地在設計一個實現數據處理系統的後端時通常使用兩種主要模型Domain模型和Table模型
Domain模型構畫了一個對象模型其中每一個實體都是通過合並了特定行為和數據的ad hoc類進行描述的一個類的任何實例都相應於該模型中一個特定的實體關系是通過跨越所涉及的類的屬性進行表達的
【譯者注】 類似於圖書館裡的書籍檢索即書籍庫(數據庫)相對穩定不變不同用戶的查詢要求是千變萬化的這種檢索就稱為ad hoc基於Web的搜索引擎也屬於這一類
在Table模型中你要為目標數據庫中的每個表格定義一個類任何要求處理數據的代碼都是在單個類的實例上定義的總結來說如果你的數據模型中包括一個Order實體那麼你應該使用域模型為每一個訂單創建一個OrderEntity對象還有一個OrderManager對象用於使用表格模型來處理所有的訂單很容易看出該訂單管理器對象十分類似Visual Studio 設計器中的表格適配器對象
在Domain模型和Table模型抽象模型中你可以發現各種具體的設計模式在大多數流行的設計模式中主要使用的是數據映射器和表格數據網關(TDG)
四 應用數據映射模式
一個數據映射(DM)對象負責把從表格中提取的原始數據加載到內存對象(這些對象被更為緊密地映射到更高一級實體關系數據模型)該DM模式尤其適合於復雜的域邏輯領域—此時數據的物理結構必須被加以提取以便直接編碼簡化閱讀和確保恰當的維護費用典型地一個高度復雜的邏輯一般都有一些額外要求例如多數據庫支持和嚴格的單元測試等在兩種情況下不同的系統發布或開發周期中的不同步驟可能要求替換整個數據映射層以便應用一種不同的邏輯針對不同的目標數據庫或是僅為了實現測試目的你進行越多的抽象並且在系統中進行越多的分層那麼以後對於你以及你的客戶將越發有益
毋庸置疑該DM模式有時看起來有些過於復雜但對於豐富的而復雜的系統來說一定是一種可行的選擇一種更為簡單的變種特別適合於簡單的邏輯實現就是活動記錄模式
在一種DM情況下你需要為抽象數據模型中的每一個實體創建許多類你將創建一個實體類(也許一個類型安全的集合類)和一個管理器類來為DAL提供公共入口點列表展示了一些具體的示例代碼
列表DM模式(Employee實體)的示例代碼
Public Class Employee
Public ID As Integer
Public FirstName As String
Public LastName As String
//……
End Class
Public Class EmployeeCollection : Inherits Collection (Of Employee)
End Class
Public Class EmployeeManager
Public Function FindAll() As EmployeeCollection
Public Function Find(ByVal empID As Integer) As Employee
Public Sub Update(ByVal emp As Employee)
Public Sub Insert(ByVal emp As Employee)
Public Sub Delete(ByVal emp As Employee)
Public Sub Delete(ByVal empID As Integer)
Public Function FindOrders(ByVal empID As Integer) _
As OrderCollection
//……
End Class
這個EmployeeManager類中提供的方法實現怎麼樣?不管在你的設計中引入了多少的抽象在某種程度上你都需要手工實現連接字符串ADONET命令和事務等內容當然你能夠把這部分代碼直接插入到EmployeeManager的方法體內然而還有一種更好的方法就是使用一組基於TDG模式的中間集合類來實現這一點圖展示了整個實現框架
圖一個使用了模式的多層應用程序架構
其基本思想是由描述層創建一個給定實體(比如說employee表格)的管理器類的實例一方面該管理器類要對描述層暴露高級對象另一方面它還負責連接到底層DAL以便進行物理數據存取在該管理器和DAL可能存在各種層為了實現更多的靈活性你可能想使用一種可替換的工廠機制並且是針對不同的數據庫的
反過來從描述層對管理器類的調用將會實例化一個數據存取提供者工廠類這個類將從配置文件信息(類和程序集)中讀取關於該工廠類的信息以便用來創建其支持的實體(如雇員顧客產品訂單等)的數據提供者
每個工廠類都要實現一個合同接口—該接口將依賴於一個方法來返回針對各種實體的數據提供者最後這些數據提供者要實現一個接口以便與管理器類中的方法相匹並使用TDG模式來得到/設置一特定數據庫中的物理數據
基於這一模式通過簡單地改變一下配置文件內的某個入口你就可以使整個系統工作在一個完全不同的數據庫之上現在你有了一些類—數據提供者—你可以在其中編寫優化的數據庫代碼—並且由於使用了基於合同的接口所以你不必去打破與上一層的關系
五 應用表格數據網關模式
在復雜的系統中你常常是把TDG模式與DM以及Factory相結合以便創建一種極其靈活的而可擴展的方案在此我必須對兩個結構化方面加以解釋首先你可以直接在管理器類的方法中編寫ADONET代碼捨棄工廠從而獲得一種純DM方案同樣你可以編寫一個純TDG方案(稍後討論)並且獲得一個類似Visual Studio 的方案
用TDG術語描述網關是一個包裝了對一個數據庫表格存取的對象而你只需要使用一個處理所有表格行的對象即可典型地該網關類中的方法將返回ADONET對象下面是一個例子
Public Class EmployeeGateway
Public Function Find(ByVal id As Integer) As IDataReader
//……
End Function
Public Function FindAll() As DataTable
//……
End Function
Public Sub Save(ByVal id As Integer )
//……
End Sub
Public Sub Insert()
//……
End Sub
Public Sub Delete(ByVal id As Integer)
//……
End Sub
:
End Class
在此你添加越多的方法該TDG模型越發進一步發展成為一個DM模型如果你把這個網關的抽象定義與前面討論的表格適配器類作一下比較那麼你會發現在這兩者之間存在一種明顯的匹配
六 總結
在基於模式進行設計時首先給人的感覺往往是有點過於抽象因為你作為一名開發人員的最終目的是要編寫出能夠實際工作的具體代碼因此模式應該成為你開發的指南而你未必在一切開發中都基於模式進行編程
根本上說應該基於你的愛好和對於一種既定方法的習慣程度來作出決定然而同時不要懼怕在復雜的問題上嘗試一種新的方式和更結構化的方法你可能很快發現你已經喜歡上它了
Visual Studio 提供的數據設計器向導生成的代碼基於經典的TDG方法進行工作其實並沒有什麼糟糕的內容當然也沒有新的或秘密的東西使用向導的關鍵在於真正了解它相對你的需要實現了什麼因此為了全面地理解Visual Studio 數據設計器的功能全面地歸納一下企業數據存取設計模式是非常必要的
本文首先解釋了Visual Studio 代碼的內在機制然後從一種模式設計的角度來分析你完全有希望對這些代碼作進一步的改進Visual Studio 數據設計器的確創建了一種結構化的有效的DAL但是你必須理解它的代碼並且著手編輯它才行—不過這種模式未必適合於復雜的應用程序開發中現在既然你已經對它有了全面的理解那麼接下來你就應該開心地試用Visual Studio 了!
From:http://tw.wingwit.com/Article/program/net/201311/11971.html