asp数据库驱动封装
一,原理图
简要介绍(详细介绍待以后对此图完成实例程序以后再附定稿):
·表现层:网页表单;
·业务层:指令中心、事件中心和实例库;
·数据层:数据字典驱动、数据库驱动、数据库:;
以上都没什么需要多于解释的地方,个人需要重点说明的是下方放在一起的表现层和数据层。
我们通常都是通过业务层来达到传递、连接业务/数据层的目的,但是在这个图的封装模式下,完全背反传统模式。
一切都从数据库开始出发,不论数据库中存在多少个表,表叫做什么名字,也不论一个表中有多少个字段,字段叫什么名字,都在系统启动的时候在自动遍历扫描后生成全局缓存,并且依据这个缓存生成数据字典,最后依据数据字典从表现层攫取并验证所需要的数据。
从另外一个方面可以说,业务层被剥离,离开数据流的传输渠道,加强了其作为指令调用、逻辑处理平台的作用,并且指挥数据层直接从表现层自动更新和修改数据。
从图中可以看到,绿色大箭头和各层内部的小箭头都是指令调用,而真正核心的数据流——黄色箭头部分,则是通过底层封装,完全自动化的完成从表现层到数据库的传输、存取动作。
在整个框架模型中,唯一需要关心数据库的地方,一个是对数据库最开始的系统设计,另外一个是根据实际需要调整程序依据数据库自动输出的表单;在业务层中的数据的存取完全是封装起来的语义操作,不涉及具体的字段。
二,思路
原来的方案:我们是首先根据数据库的字段和实际需求设计Web表单,然后从Web表单获取提交的数据集,然后在服务段将提交的数据集和数据库的字段一一对应,然后再一一作过滤和处理……
现在的方案:直接从数据库生成框架缓存,将每一个表的字段及其相关属性(类型要求、必填、长度、默认值……)储存在全局数组中。当外部提交某张表单时,从对应的全局数组中生成相应的Dictionary对象,然后依据这个和数据表完全映射的Dictionary遍历获取对应的提交值,由此替代了一一对应和读取的繁琐过程。
数据库除了有与表单交互得到数据,还需要根据参数得出数据并显示的部分
当外部提交某张表单时,从对应的全局数组中生成相应的Dictionary对象。这一部分的实现有几个步骤,都在Dictionary类中。
首先,程序抓取到表单的提交动作(Action),然后根据这个动作激活底层驱动;
然后在字典驱动中,通过Creat()方法获取对应表单在appliction中的数组缓存,其中指定表单的参数是通过在业务逻辑的类自定义传入的,而这些映射着表及其字段的二维数组是在整个程序启动的时候遍历扫描到全局变量中的;
然后通过GetRequest()方法,依次遍历这个表的每一个字段(这里表现为遍历数组),并且把抓取到数据的字段新建为Dictionary对象,即:ObjDictionary.Add Key,Item。
其后的处理有很多变化,一般是先用ValidTpye()方法遍历和验证抓取到的数据类型,ValidFill()方法验证是否为必填项目等等,最后交给数据访问层组合SQL语句入库。
实现部分被简化为:
for i=0 to Ubound(KeysArray)-1
Key=KeysArray(i,0)
Item=Request(md5(Key))
objDict.Add Key,Item
next
也就是说,这是和传统方案完全相反的思路,这个思路保证了所获取的数据一定是数据库所需要的数据,数据库要求的数据类型或者必须为空的数据如果出现异常则必然会出错,等等。
最后在实现表单处理的语句简化为,其他的一切操作都被封装在类中:
Call System_Initialize()
Dim objUser '新建对象
Set objUser = new TUser
objUser.Table="Comm_User" '指定数据表
If objUser.Creat Then '建立表的Dictionary对象
objUser.ValidAndTransfer() '获取数据、验证并转入最终的数据驱动层
objUser.Update() '更新该表数据
End IF
Set objUser = nothing
Call System_Terminate()
与之配套的另外一个方面是从缓存的数据表框架中按照实际表单的需要自动生成Web表单,显示在客户端。
在SQL Server中遍历当前数据库的所有用户表
SELECT Table_name
FROM INFORMATION_SCHEMA.TABLES
WHERE (TABLE_TYPE <> 'VIEW')
Table_name:表名;
TABLE_TYPE:表的类型;
参见:SQL Server联机手册,T-SQL参考,信息架构视图。
又及:ACCESS下也可实现相关的功能[1]
在SQL Server中遍历指定表的字段及属性
SELECT Column_name,IS_NULLABLE,DATA_TYPE
FROM INFORMATION_SCHEMA.COLUMNS
WHERE (TABLE_NAME = 'myTableName')
TABLE_NAME:表名;
Column_name:列名;
IS_NULLABLE:是否允许为空;
DataType:系统数据类型;
ORDINAL_POSITION:列标识号;
COLUMN_DEFAULT:列的默认值;
CHARACTER_OCTET_LENGTH:以字节为单位的最大长度,适于二进制数据、字符数据,或者文本和图像数据。否则,返回 NULL。
从数据库生成当前库所有表全局Array缓存
strSQL="SELECT Table_name FROM INFORMATION_SCHEMA.TABLES WHERE (TABLE_TYPE<>'VIEW')"
Set objRS_table= objConn.Execute(strSQL)
do while not objRS_table.EOF
strSQL="SELECT Column_name,DATA_TYPE,IS_NULLABLE,COLUMN_DEFAULT,CHARACTER_OCTET_LENGTH FROM INFORMATION_SCHEMA.COLUMNS WHERE (TABLE_NAME = '"& objRS_table("Table_name") &"')"
set objRS_column=server.createobject("adodb.recordset")
objRS_column.open strSQL,objConn,1,1
Dim i,TableTemp
i=0
ReDim TableTemp(objRS_column.RecordCount,4)
do while not objRS_column.EOF
TableTemp(i,0)=objRS_column(0)
TableTemp(i,1)=objRS_column(1)
TableTemp(i,2)=objRS_column(2)
TableTemp(i,3)=objRS_column(3)
TableTemp(i,4)=objRS_column(4)
i=i+1
objRS_column.movenext
loop
Set objRS_column= nothing
application(objRS_table(0))=TableTemp
objRS_table.movenext
loop
数据驱动层
<%
' '底层A:对DataBase操作的封装。 '返回错误代码头:DB '
Class TDBDriver
Public objDict
Private Table
Private KeysArray
Private ItemArray
Private objRS
Private strSQL
Private SQL_Start
Private SQL_Main
Private SQL_Join
Private SQL_Where
Private SQL_Order
Private SQL_Group
Public PageSize
Private ErrorMsg
'插入一条数据或者更新指定的条目
Public Function Update()
If objDict.Item(KeysArray(0,0))="" Then
SQL_Start="Insert into "& Table
SQL_Main=" ("
'从有数据的部分对应更新入数据库
For i=1 to objDict.Count-1
If Not ItemArray(i)="" Then
SQL_Main= SQL_Main & KeysArray(i,0) &","
End If
Next
'去掉最后一个“,”
SQL_Main=Left(SQL_Main,Len(SQL_Main)-1)
SQL_Main= SQL_Main &") Values("
For i=1 to objDict.Count-1
If Not ItemArray(i)="" Then
If KeysArray(i,1)="int" Then
SQL_Main= SQL_Main & objDict.Item(KeysArray(i,0))
Else
SQL_Main= SQL_Main &"'"& objDict.Item(KeysArray(i,0)) &"'"
End if
SQL_Main= SQL_Main &","
End If
Next
'去掉最后一个“,”
SQL_Main=Left(SQL_Main,Len(SQL_Main)-1)
SQL_Main= SQL_Main &")"
Else
SQL_Start="Update "& Table &" Set "
For i=1 To objDict.Count-1
If Not ItemArray(i)="" Then
SQL_Main= SQL_Main &" ("& KeysArray(i,0) &"="
If KeysArray(i,1)="int" Then
SQL_Main= SQL_Main & objDict.Item(KeysArray(i,0))
Else
SQL_Main= SQL_Main &"'"& objDict.Item(KeysArray(i,0)) &"'"
End if
SQL_Main= SQL_Main &"),"
End IF
Next
'去掉最后一个“,”
SQL_Main=Left(SQL_Main,Len(SQL_Main)-1)
SQL_Where=" Where "& KeysArray(0,0) &"="& objDict.Item(KeysArray(0,0))
End if
strSQL=SQL_Start & SQL_Main & SQL_Where
'objConn.Execute(strSQL)
Response.Write strSQL
Update=True
End Function
'删除数据
Public Function Delete()
If objDict.Item(KeysArray(0,0))="" Then Call ShowError(ErrorMsg,01) :Exit Function
SQL_Start="Delete From "& Table
SQL_Where=" Where "& KeysArray(0,0) &"="& objDict.Item(KeysArray(0,0))
strSQL=SQL_Start & SQL_Where
objConn.Execute(strSQL)
Delete=True
End Function
'返回单条数据
Public Function ReturnSingle()
If objDict.Item(KeysArray(0,0))="" Then Call ShowError(ErrorMsg,02) :Exit Function
SQL_Start="Select * From "& Table
SQL_Where=" Where "& KeysArray(0,0) &"="& objDict.Item(KeysArray(0,0))
strSQL=SQL_Start & SQL_Where
Set objRS =objConn.Execute(strSQL)
If objRS.EOF or objRS.BOF Then
Call ShowError(ErrorMsg,03)
Else
For i=1 To Ubound(objDict.Items)-1
objDict.Item(KeysArray(i,0)) = objRS(i)
Next
End IF
Set objRS =Nothing
ReturnSingle=objDict
End Function
'返回分页数据
'需要继承回传的数据
Public Function ReturnList()
'必须指定页长、页数
If PageSize="" Then Call ShowError(ErrorMsg,0) :Exit Function
End Function
Public Function Transfer(ExternalDict)
Set objDict=ExternalDict.objDict
'参数导入,只是为了书写方便
Table=ExternalDict.Table
KeysArray=ExternalDict.KeysArray
ItemArray=objDict.Items
End Function
Private Sub Class_Initialize()
ErrorMsg="DB"
'传入FormDriver处理过的Dictionary
End Sub
Private Sub Class_Terminate()
'返回FormDriver处理过的Dictionary
End Sub
End Class
底层B:对Dictionary操作的封装。
'返回错误代码头:DC
' <code vb> Class TDictionaryDriver Public Table Public KeysArray Public objDict Private Key Private Item Private ErrorMsg '根据系统缓存导入框架 '报错信息 Public Function Creat() '必须指定数据表 If Table=”” Then Call ShowError(ErrorMsg,01) :Exit Function '必须是系统缓存中已经存在的数据表 If IsNull(application(Table)) Then Call ShowError(ErrorMsg,02) :Exit Function '导入数据表框架 KeysArray=application(Table) End Function '根据数据表框架-获取[过滤]数据 '通过加密的方案解决表单字段和数据库字段的异步问题 Public Function GetRequest() for i=0 to Ubound(KeysArray)-1 Key=KeysArray(i,0) Item=Request(md5(Key)) 'Item=Request.QueryString(md5(Key)) 'Item=Request.Form(Key) objDict.Add Key,Item next '形成Dictionary对象 GetRequest=True End Function '根据数据表框架-效验获取的数据 Public Function Valid() '注入转换和过滤 '必填项 If objDict.Item(KeysArray(0,0))=”” Then '对于新增数据,必填项目不能为空 '允许更新操作跳过必填项目遍历进行部分更新 for i=1 to Ubound(KeysArray)-1 '跳过主键遍历 If Trim(KeysArray(i,2))=“No” And objDict.Item(KeysArray(i,0))=”” Then Call ShowError(ErrorMsg,03) :Exit Function next End IF '字段类型要求 for i=0 to Ubound(KeysArray)-1 '效验数据类型要求 If KeysArray(i,1)=“int” Then If IsNumeric(objDict.Item(KeysArray(i,0)))=0 Then Call ShowError(ErrorMsg,04) :Exit Function If objDict.Item(KeysArray(i,0))>2147483647 or objDict.Item(KeysArray(i,0))←2147483647 Then Call ShowError(ErrorMsg,05) :Exit Function ElseIf objDict.Item(KeysArray(i,0))<>”” And KeysArray(i,1) =“datetime” Then If IsDate(objDict.Item(KeysArray(i,0)))=0 Then Call ShowError(ErrorMsg,06) :Exit Function ElseIF KeysArray(i,1)=“bit” Then If (Not objDict.Item(KeysArray(i,0))=0) And (Not objDict.Item(KeysArray(i,0))=1) Then Call ShowError(ErrorMsg,07) :Exit Function End If '效验字段长度 If IsNumeric(KeysArray(i,4)) And Len(objDict.Item(KeysArray(i,0)))>=KeysArray(i,4) Then Call ShowError(ErrorMsg,08) :Exit Function '默认值 next Valid=True End Function '从数据库框架和Dictionary还原出完整的表单,该表单需要具体对象类根据实际需求进行进一步处理 '通过加密的方案解决表单字段和数据库字段的异步问题 Public Function ReturnForm() Dim strForm strForm=”<form action=”””” method=”“post”” id=”””& MD5(Table) &”””><ul>” &chr(10) strForm=strForm &”<li><input id=”””& MD5(KeysArray(0,0)) &””” type=”“hiddden”” value=”””& objDict.Item(KeysArray(0,0)) &”””></li>” &chr(10) for i=0 to Ubound(KeysArray)-1 '效验数据类型 If KeysArray(i,1)=“int” Then 'Radio 'Select 'Checkbox strForm=strForm &”<li><input id=”””& MD5(KeysArray(i,0)) &””” type=”“text”” value=”””& objDict.Item(KeysArray(i,0)) &”””></li>”&chr(10) ElseIf KeysArray(i,1) =“datetime” Then strForm=strForm &”<li><input id=”””& MD5(KeysArray(i,0)) &””” type=”“text”” value=”””& objDict.Item(KeysArray(i,0)) &”””></li>”&chr(10) ElseIF KeysArray(i,1)=“bit” Then strForm=strForm &”<li><input id=”””& MD5(KeysArray(i,0)) &””” type=”“text”” value=”””& objDict.Item(KeysArray(i,0)) &”””></li>”&chr(10) ElseIF KeysArray(i,1)=“text” Then strForm=strForm &”<li><textarea id=”””& MD5(KeysArray(i,0)) &””” type=”“text””>”& objDict.Item(KeysArray(i,0)) &”</textarea></li>”&chr(10) End If next strForm=strForm &”</ul><form>” &chr(10) Response.Write strForm ReturnForm=True End Function Private Sub Class_Initialize() '创建Dictionary对象 Set objDict=CreateObject(“Scripting.Dictionary”) ErrorMsg=“DC” End Sub Private Sub Class_Terminate() '释放Dictionary对象 Set objDict=nothing End Sub End Class </code> '
'交互层,根据实际需要定制结合对Dictionary和DataBase的操作,定义针对对象的直接操作。
'返回错误代码头:UR
'**
Class TUser
Public Table
Private objDictionary
Private objDataBase
Private ErrorMsg
Public Function Update()
iF objDataBase.Update Then Update=True
End Function
Public Function Delete()
iF objDataBase.Delete Then Delete=True
End Function
Public Function DrawForm()
iF objDictionary.ReturnForm Then DrawForm=True
End Function
Public Function ValidAndTransfer()
objDictionary.GetRequest()
If objDictionary.Valid Then
Call objDataBase.Transfer(objDictionary)
Else
Call ShowError(ErrorMsg,01) :Exit Function
End If
End Function
Public Function Creat()
If Not Table="" Then
objDictionary.Table=Table
objDictionary.Creat()
End If
Creat=True
End Function
Private Sub Class_Initialize()
ErrorMsg="UR"
Set objDictionary= new TDictionaryDriver
Set objDataBase = new TDBDriver
End Sub
Private Sub Class_Terminate()
Set objDictionary= Nothing
Set objDataBase = nothing
End Sub
End Class
''''''''''''''''''''''''
Call System_Initialize()
Dim objUser
Set objUser = new TUser
objUser.Table="Comm_User"
If objUser.Creat Then
'objUser.ValidAndTransfer()
'objUser.Update()
Call objUser.DrawForm()
End IF
Set objUser = nothing
Call System_Terminate()
''''''''''''''''''''''''
%>
代码下载
VBScript因为语言本身的限制,很多功能的实现都会变得没有必要的复杂,或者根本就不可能实现,有兴趣的可以用Javascript重写这个框架,那应该就可以比较轻松地实现多表联合查询了。
所以,现在这个框架仅实现了在单表状态下的操作,觉得主要的功能都有了。
用这个框架写的写一个很简单的网站动态发布系统fyautoparts.com代码下载,另外请注意这个实例为每个表写了单独的业务逻辑类,其实并非必要可以简化。
安装指南:
1、下载源文件包;
2、把fyautoly文件夹下的所有文件解压;
3、在SQL Server新建数据库auto_website,然后将auto_website.dat文件还原到这个数据库;
系统管理界面在:
/web/admin/
用户名:Aether
密码:111111
参考