我们之前曾经说过,UserDefinedTable用三张表,就完成了支持无限字段的动态窗体的数据结构,这似乎已 经是绝对不可能再精简的数据结构了(当然,还需要借助系统的Users表,来区分用户),这三张表是UserDefinedFields、 UserDefinedRows和UserDefinedData这三张表,所有的用户数据,都存储在UserDefinedData这张表中,我们将这个数据结构截一张图放在下面,让大家可以看清楚。
为了存储所有格式的字段(如日期型、大文本型等等),因此,FieldValue采用了ntext字段。其实,这样的存储在DotNetNuke中已经有了,就是我们的模块设置表TabModuleSettings,为了存储各种类型的数据,比如布尔型、整数型、日期型 等等,但是TabModuleSettings采用的是nvarchar(2000)。
这样的数据结构就是为了可以为一条记录提供无限的字段数量,而不需要我们去动数据结构;这样的数据库设计方式其实在国内各种应用里面也是屡见不鲜的。我们举一个例子,来讲一下数据是如何存储的,比如,我们有一个定义的窗体,是用来做人员登记的,存储姓名、性别和年龄 (靠,非常弱智的例子),我们最终的结果是这样的:
张三 男 25
(为了简单起见,性别我们也直接用字符串了,不过为了避免砖头横飞,还是解释一下。)而在数据库中,是这么存储的,见下图:
上面这些,其实写过程序的朋友们基本上都比较清楚了,这里只是做一个简单的介绍而已。这样的存储,比较痛苦的就是如何把数据“拿出来”了,比如我们写一条SQL语句,把RowID为2的那三个字段拿出来,形成一张横表的话,需要用到LEFT JOIN方法,我们将SQL语句写在下面:
SELECT R.UserDefinedRowID, D1.FieldValue As 姓名, D2.FieldValue As 性别, D3.FieldValue As 年龄
FROM UserDefinedRows R
LEFT JOIN UserDefinedData D1 ON R.UserDefinedRowID=D1.UserDefinedRowID AND D1.UserDefinedFieldID=10
LEFT JOIN UserDefinedData D2 ON R.UserDefinedRowID=D2.UserDefinedRowID AND D2.UserDefinedFieldID=11
LEFT JOIN UserDefinedData D3 ON R.UserDefinedRowID=D3.UserDefinedRowID AND D3.UserDefinedFieldID=12
WHERE R.UserDefinedRowID=2
FROM UserDefinedRows R
LEFT JOIN UserDefinedData D1 ON R.UserDefinedRowID=D1.UserDefinedRowID AND D1.UserDefinedFieldID=10
LEFT JOIN UserDefinedData D2 ON R.UserDefinedRowID=D2.UserDefinedRowID AND D2.UserDefinedFieldID=11
LEFT JOIN UserDefinedData D3 ON R.UserDefinedRowID=D3.UserDefinedRowID AND D3.UserDefinedFieldID=12
WHERE R.UserDefinedRowID=2
而最后得到的结果,就是我们希望的一张横表,如下图所示:
在论坛中,UDT的TeamLeader Sebastian Leupold曾经这样描述过他的UDT数据结构,大家有兴趣的话可以去看一下。
OK,现在想象一下,如果我们有30个自定义字段,这个SQL语句会有多长呢?而一个自定义的Form 中,有30个字段,应该不是什么过分的要求吧?更重要的是,LEFT JOIN这种方式,还是效率比较低下的。而更过分的是,我们的UserDefinedTable模块,采用了应该是更为低下的方式来处理数据,就是将数据一条条取出来,然后在内存中动态生成一张DataTable,然后再将这个DataTable绑定到显示控件上。按照我个人的理解,我觉得这种方式毫无疑问是比LEFT JOIN更为效率低下的一种处理方式,所以,在另外一个帖子里(抱歉,翻了半天,仍然找不到那个帖子,顺便鄙视一下DotNetNuke Forum的搜索功能,基本上没有能用的时候),Sebastian Leupold也亲口承认说,UDT对于超大量的数据是不适合的。所以,其实UDT的问题,是“结构性问题”,如果我们需要超越UDT,开发我们的 Form,并且可以容纳比如百万级数据的话,一定要重新设计一下UDT的结构,将其中有用的为我所用;其中不好的予以改进。
下一节我们讨论如何对这个数据结构进行优化,从而达到我们的要求。