我想問的第一個問題是:我真的需要這樣做嗎?類型化的DataSet設計器已經爲您提供了定義存儲過程和DataTable之間映射的工具。如果小心設計DataSet,則每個DataTable已經有一個Fill方法。重新發明這個輪子有意義嗎?
我認爲這可能。保持該映射的方法非常酷,但映射中的所有內容都會在編譯時凍結。如果你想改變映射,你需要重建你的程序集。此外,類型化的DataSet設計不處理返回多個結果集的存儲過程。如果您想一般地映射參數和值,則必須使用反射來獲取Fill方法中的參數列表。如果你看看那些因素(以及其他我沒有想到的),那麼使用現有的工具可能不是一種好的選擇。
在這種情況下,我認爲您的目標是能夠從一系列存儲過程中填充數據集,其中的代碼儘可能少地瞭解實現細節。所以這是一個將由元數據驅動的過程。當你有一個由元數據驅動的進程時,從長遠來看,最重要的是維護進程使用的元數據是多麼容易。一旦你得到代碼的工作,你可能不會觸及它。但你會不斷調整元數據。
如果從這個角度來看問題,我想要做的第一件事就是設計一個類型化的DataSet來包含元數據。這給我們帶來了一堆東西,我們就會否則必須弄清楚:
- 一個持久格式
- 一個簡單的路徑,建立一個綁定的UI
- 同樣直接的途徑,以在持續的元數據數據庫,如果我們決定沿着這條路走下去
- 導航數據的對象模型。
在這個DataSet中,您將擁有一個DataSetType表,該DataSetType表的鍵名是您希望能夠填充的每個類型化數據集的類型。它會有一個StoredProcedures表,每個SP被調用一行。這將有兩個子表,即Parameter和DataTableType。對於SP預期返回的每個結果集,將有一個DataTableType行,按序號排序。 DataTableType表將有一個子ColumnMapping表。在該表中,您將維護結果集中的列與您正在填充的表中的列之間的映射。
確保您的所有DataRelation都是嵌套的,並且您已經給關係給出了合理的名稱。 (我喜歡FK_childtablename_parenttablename
。)
一旦你有了這個,班級設計變得非常簡單。這個類有元數據的DataSet,連接等的引用,,並將它暴露的方法與此簽名:
public void FillDataSet(DataSet targetDs, Dictionary<string, Dictionary<string, KeyValuePair<string, string>> parameterMap);
你開始使用targetDs的類型,找到頂級DataSetType行。然後,所有私有方法遍歷DataTable.GetChildRows()返回的DataRows列表。並且您可以爲類設計添加一個或兩個事件,以便在執行操作時可以引發事件,讓調用應用程序知道它的進展情況。
也許我期望重構這個設計的第一個地方是讓我對填充過程有更細緻的控制。例如,按照設計,每個類型的DataSet只有一組SP。如果我只想填充DataSet的子集,該怎麼辦?按照設計,我不能。但是您可以輕鬆地將DataSetType表的主鍵分爲兩部分,其中部分爲DataSet類型和一些字符串鍵(名稱如SPSetName或OperationName),並將該鍵的第二部分添加到FillDataSet參數列表。
你用什麼機制來填充各種DataTables?一個DataReader? TableAdapter的?還有別的嗎? – 2008-10-23 17:57:39
我正在使用SqlDataAdapters。我已經更新了這個問題來說明問題。 :) – 2008-10-23 18:57:46