06年底的時候,關於UDT的結構和其他的一些問題,和Sebastian Leupold通過郵件,因為當時費了很大的勁才弄明白數據到底是怎麼給弄出來的,DotNetNuke裡面像這麼難懂的代碼還是不太多的,我的建議是把 UDT的數據結構稍微改一下,弄成讓大家更舒服一點的,不過估計是大家交流上還是有點障礙,畢竟E文都不是母語(SL是德國佬);後來想:算了,還是自己弄吧,於是從這個數據結構出發,把它給優化了一下,成了我的數據結構,希望不會讓大家覺得太爛。
首先再貼一張圖,分析一下UserDefinedTable的情況
(原來的數據結構存儲)
我把三張表的數據弄到一塊了,這樣大家可以看得更清楚一點。上圖中可以看到,UserDefinedFields是一個字段定義器存放的數據,比如我們的字段名稱、初始值、順序等,這個表可以理解為一個“結構表”;而下面的UserDefinedRows是“主記錄表 ”,UserDefinedData是“從記錄表”。我們的表格結構是存放在Fields表裡面的,而所有的表格內容,都是存放在Rows和Data這兩張表中的。
大家可以看到,UserDefinedRows這張表只有兩個字段,其實,除了幾乎每個用戶開發模塊都有的ModuleId(是為了在不同的模塊中顯示不同的數據),那麼,就只有一個字段,也就是UserDefinedRowID,這張表太浪費了!
而我們再回頭想一下我們通常使用的列表/窗體,其實,對於“列表/窗體”這種模式來說,顯示在列表上的必然只是有限的幾個字段而已,而大量的字段,是不需要顯示在列表上的,所以,我們的改造就是,把需要在列表上顯示的,盡量的放在UserDefinedRows這張表中,那麼,其實,我們讀取數據的時候,就不需要弄那麼復雜的LEFT JOIN,也不需要在內存中動態生成DataTable了,這種方式,當然是可以大大提高執行效率的。改進後的數據結構,可能是如下圖所示的:
OK,其實看過這張圖大家應該知道我的想法了,就是把數據分成兩部分,一部分是需要(或者是可能需要)在列表上進行展示的(還有,比如要在查詢條件中出現的、要參與系統查詢接口的等等),我們盡量將之放在UserDefinedRows這張表中;另外一部分是只是在打開表格中才會用到或者讀取的,我們將之放在UserDefinedData這張表中。這個時候,如果我們再要讀取數據的話,那就非常簡單的,可能的SQL語句就是如下這種樣式的:
SELECT UserDefinedID, Field1 AS 姓名, Field2 AS 性別, Field3 AS 年齡 FROM UserDefinedRows
只是在編輯或者查看詳細的內容的時候,我們才需要去讀取UserDefinedData這張表,所以,效率上肯定不會有問題。既然我們對這個數據結構作了修改,那麼,字段定義表UserDefinedFields這張表的結構當然也需要修改一下,至少要標明哪些字段是“基本字段”(也就是在 UserDefinedRows中出現的字段),哪些是擴展字段(也就是在UserDefinedData中出現的字段),其他的,根據我們的業務需要去進行擴展就可以了。
在讓用戶進行表單定義的時候,可以告訴用戶,如果需要在列表上顯示和查詢的,就盡量使用基本字段;其他的,則任意定義。
通過這種方式,我們把UserDefinedTable這個模塊往前提升了一步,仍然支持無限的字段定義,但是,在缺省的Control(也就是View界面)上讀取數據的時候,我們盡量拋棄UDT原來的非常讓人頭疼的方式。
為了讓數據更加規范,我們在增加UserDefinedRows表的字段的時候,做嚴格的數據類型限制(而不需要像 UDTData表那樣統一的采用ntext類型,或者是varchar類型),這樣的好處就是存儲的數據是絕對嚴格的,程序出錯的幾率更小。如果大家用 varchar字段存儲過日期格式、數值格式,而又碰到過需要對這些字段進行拼湊SQL語句查詢的話,大家就明白我在說什麼了,那種出錯的痛苦(數據格式不規范,如本來應該是日期型,結果實際存儲的不是,於是,日期轉換函數報錯),簡直就是讓人欲哭無淚。
所以……,是的,在大家崩潰之前,我要告訴大家,我已經把UserDefinedRows的兩個字段擴展到幾十個字段了,就是上圖這個龐然的數據結構,看到其中的ParentID了?是的,我讓這個玩意兒也支持樹形結構了!如果大家有足夠的耐心給我足夠的時間的話,應該可以看到我的解釋。(還有FormID、KeyID等,也需要解釋)
反倒是UserDefinedData這張表,和原來沒什麼太大的不同,這裡我們就不貼圖了。
好了!為了遍歷和查詢的快捷性以及准確性,我們把UserDefinedRows這張表給擴展了,增加了數據結構,並且要求嚴格限制數據類型;而為了支持動態窗體的無限字段支持,我們仍然保留了UserDefinedData這張表。不要LEFT JOIN,不要在內存裡面動態生成DataTable,那都是太浪費效率的方式。
弄完數據結構之後,馬上我們就面臨一個問題了,那就是用存儲過程是不太好更新我們的數據結構的,所以,下面我們要做的事情,就是把DotNetNuke傳統的使用存儲過程保存數據的方式也改掉(當然,仍然沒有動及DotNetNuke的開發結構,這個是我們不能動的)。我們下一部分來談這個問題,我們將會使用哈希表的結構,來動態的更新這張表。