DotNetNuke自定义窗体模块的数据结构(三)


在接触国外的CMS等Open Source产品之前,老实说,我写过的存储过程,包括SQL Server的、Oracle的,加起来绝对不会超过5个,而且还基本上都是从网上抄袭的,主要是觉得太麻烦:嗯,是的,如果数据库设计的不够好,经常需要改动,比如加一个字段,修改一下字段类型的话,需要从数据表、存储过程、调用等一路改上来,确实是挺麻烦的。不过习惯了之后,发现用存储过程确实有它的好处,也被迫养成了对数据库设计要每个字段都斟酌半天的习惯,所以,我们看到DotNetNuke有近乎上千个存储过程(安装了所有的附加模块之后)。

  我现在非常喜欢使用存储过程的方式来操作数据库——不过,诚如我们在《DotNetNuke自定义窗体模块的数据结构(二)》中所说的那样,由于我们修改了数据结构,所以,存储过程在这里使用是不太适合的。唉,好吧,我声明:我所说的并不代表我的意思,我对我说的话不承担任何责任

  我们在(二)中重新把UDT的UserDefinedRows这张表(在我们的模块中已经改名了)做了修改,如果是希望在列表上显示的,或者是参与查询的,我们都作为基本字段放在列表中;而其他的字段则作为扩展字段放在扩展表中,在用户进行定义的时候,可以选择是使用基本字段,还是扩展字段。当然,在这种情况之下,基本字段就不可能被“用完”,在某一个Form之中,我们可能只需要基本字段中的几个而已,其他剩余的我们都不需要用到,简而言之,也就是我们需要更新的字段是运行时决定的,而不是设计时决定的。而这个时候,如果我们在进行INSERT或者UPDATE操作的时候,是对所有的字段都操作一遍的话,不但是有点怪,而且也容易造成错误,比如,日期型、整数型等的字段,本来明明是没有内容的,但是我们非要INSERT入内容,会出现错误,或者是不正确的初始数据,我们希望,没有使用到的字段,就保留其为NULL就好了,不需要对该字段进行操作(大家可以插入空值或者是String.Empty试试,会觉得很头疼)。
所以,我们需要在运行时生成SQL语句,我们把这个函数放在下面,供大家参考。

1    PublicOverridesFunctionAddHashRow(ByValfieldAsHashtable)AsInteger
2      DimsqlCommAsSqlCommand=NewSqlCommand()
3
4      DimstrSqlAsString="INSERTINTORedstartFormRow("
5
6      DimstrFieldAsString=""
7      DimstrParmAsString=""
8
9      ForEachdicAsDictionaryEntryInfield
10        IfstrField<>""Then
11          strField=strField&","
12        EndIf
13        strField=strField&dic.Key.ToString()
14
15        IfstrParm<>""Then
16          strParm=strParm&","
17        EndIf
18        strParm=strParm&"@"&dic.Key.ToString()
19
20        sqlComm.Parameters.Add(NewSqlParameter("@"&dic.Key.ToString(),GetNull(dic.Value.ToString())))
21      Next
22      strSql=strSql&strField&")VALUES("&strParm&")"
23
24      strSql=strSql&";selectSCOPE_IDENTITY()"
25
26      DimsqlConnAsNewSqlConnection()
27      sqlConn.ConnectionString=ConnectionString
28      sqlConn.Open()
29      sqlComm.Connection=sqlConn
30
31      sqlComm.CommandText=strSql
32
33      ReturnCType(sqlComm.ExecuteScalar(),Integer)
34    EndFunction

这个函数,是放在SqlDataProvider.vb文件中的。

  而按照DotNetNuke通常的方式,是使用存储过程来和数据库打交道的,也就是如下图所示:

  在我们的处理中,没有将数据库的操作交给存储过程来完成,而是在SqlDataProvider里面,就是用SqlCommand来执行SQL语句,执行动态的SQL插入动作。使用存储过程当然可以获得更高的执行效率,不过,通过SqlCommand也是可以的方式。除了INSERT动作之外,我们的 Update动作也是动态的,仍然是通过动态拼凑SQL语句的方式,对数据表进行更新。而在这个函数中,我们仍然调用select SCOPE_IDENTITY(),以便可以马上返回我们的值,以方便我们在程序中可能的马上要对这一条数据进行继续处理。

  在上述的方式中,我们使用到了哈希表来存储数据,哈希表的Key对应我们的字段名称,而Value则对应用户表单中输入的内容。于是,在我们的动态窗体页面上,当页面进行保存的时候,我们需要将所有的用户控件的内容读取到哈希表中,然后再调用本函数,进行插入,或者更新。

  这只是我们的基本字段的部分,除了基本字段,我们还有扩展字段,扩展字段是对UDT的UserDefinedData表(对于我们来说,是RedstartFormRowData表)进行插入,或者更新。这个就非常简单了,我们使用存储过程来实现就可以了。

  好了,大家还记得我们曾经在《基于DotNetNuke的动态窗体支持(二)》这篇文章中定义了一个EditControls的集合吗?这个集合中包含了我们所有的用户自定义控件。OK,我们在保存的时候,需要做的事情就是

  1、遍历EditControls集合,找到所有的基本字段,将之送到一个哈希表中。然后,调用我们上面的AddHashRow的函数去保存基本字段;

  2、再遍历一遍EditControls集合,基本字段置之不理,找到扩展字段,然后逐个的调用我们保存扩展字段的存储过程,将之保存到扩展表中;

  以上就是我们对自定义窗体结构的保存过程,在这里,我没有为我们的数据结构定义对应的对象,因为我觉得,对于这样的结构,定义对象并不太好,当然,这就导致了IDataReader的大量使用,也出现了一些问题,到时候我们再来讲。


« 
» 
快速导航

Copyright © 2016 phpStudy | 豫ICP备2021030365号-3