asp数据库驱动封装

一,原理图

http://www.deepcast.net/wiki/lib/exe/fetch.php?hash=e4517d&media=http%3A%2F%2Fwww.deepcast.net%2Fdeepcast%2FUserFiles%2F2006-8%2F18%2F2006818132531360.gif

简要介绍(详细介绍待以后对此图完成实例程序以后再附定稿):

  ·表现层:网页表单;

  ·业务层:指令中心、事件中心和实例库;

  ·数据层:数据字典驱动、数据库驱动、数据库:;

  以上都没什么需要多于解释的地方,个人需要重点说明的是下方放在一起的表现层和数据层。

  我们通常都是通过业务层来达到传递、连接业务/数据层的目的,但是在这个图的封装模式下,完全背反传统模式。

  一切都从数据库开始出发,不论数据库中存在多少个表,表叫做什么名字,也不论一个表中有多少个字段,字段叫什么名字,都在系统启动的时候在自动遍历扫描后生成全局缓存,并且依据这个缓存生成数据字典,最后依据数据字典从表现层攫取并验证所需要的数据。

  从另外一个方面可以说,业务层被剥离,离开数据流的传输渠道,加强了其作为指令调用、逻辑处理平台的作用,并且指挥数据层直接从表现层自动更新和修改数据。

  从图中可以看到,绿色大箭头和各层内部的小箭头都是指令调用,而真正核心的数据流——黄色箭头部分,则是通过底层封装,完全自动化的完成从表现层到数据库的传输、存取动作。

  在整个框架模型中,唯一需要关心数据库的地方,一个是对数据库最开始的系统设计,另外一个是根据实际需要调整程序依据数据库自动输出的表单;在业务层中的数据的存取完全是封装起来的语义操作,不涉及具体的字段。

二,思路

原来的方案:我们是首先根据数据库的字段和实际需求设计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

参考

ASP数据库封装驱动·实例下载

ASP数据库封装驱动

ASP-VBScript下程序模型图