帝国软件
  设为首页 加入收藏 关于我们
 
解密帝国网站管理系统
栏 目:
 
您的位置:首页 > 技术文档 > ASP编程
远程数据服务
作者:佚名 发布时间:2005-04-02 来源:不详
 

   远程数据服务(Remote Data Services,RDS)是允许我们处理客户端数据的一系列服务的统称。现在不用担心这方面的问题,因为RDS本身就是ADO的一部分,只有在需要传送和使用客户端数据时,才会使用。实际上RDS是由几个组件构成的。图10-1说明了这些组件以及它们之间是如何协同工作的。

组件似乎很多,但并不是所有的组件在每种情形下都被使用,实际上有一些不是RDS的一部分。然而这里还是把所有可能出现的组件都放在了图上,以备需要时查看。图10-1分成了两部分,因为使用客户端数据需要一些向客户端传送数据的方法,同时数据一旦到达客户端,也需要一些管理数据的方法。我们先从服务器端开始。

10.2.1 RDS服务器组件
虽然RDS用于传送和访问客户端数据,但其确实有一些基于服务器的组件。这是必需的,因为肯定需要某种方式将数据传送到客户端。因此有了一系列能访问数据并允许发送数据到客户端的服务器组件。我们把实际的数据传送称为调度(marshal)。
服务器端组件图的最上端是数据存储,由OLE DB提供者访问。它并不是RDS的一部分,但这表示只要有相应的OLE DB提供者,就可以通过RDS在客户端使用任何数据。至于如何处理服务器上的数据,可以有两种选择:
· 数据工厂(DataFactory)是缺省的用于访问数据存储的服务器端组件。它作为服务器端RDS组件的一部分安装在计算机上,除了能从数据存储中获取数据外,还为服务器处理发送到客户端以及从客户端发送来的数据。
· 自定义组件只是一个普通的提供了数据传送方法的COM组件。当数据工厂不能提供所需的功能时,可以使用自定义组件。本章将介绍一个简单的组件例子,在本书的后面还有一个更复杂的例子。
Web服务器使用这两种组件作为客户和服务器数据的接口。

10.2.2 RDS客户组件
在客户端先从底端的DataSpace对象开始,该对象作为客户端的一部分与数据工厂或自定义对象协同工作。DataSpace对象是一个代理对象,负责与服务器进行通信,同时也是数据传输的通道(或者通常所说的调度)。DataSpace对象是用客户端脚本语言或用HTML语言中的<OBJECT>标记创建的COM对象。在本章后面会看到关于这方面的例子。
DataSpace对象上面是数据源对象(Data Source Object,DSO),负责存储客户端数据。一个数据源对象包含一个ADO数据记录集,与客户数据缓存共同管理数据。客户数据缓存只是一种管理客户端数据的客户光标服务。同时数据源对象又是一个COM对象,与DataSpace对象类似,也可以通过客户端脚本或使用HTML语言中的<OBJECT>标记来创建。同样,在本章稍后也会介绍关于这方面的一些例子。
数据源对象的上面是数据绑定管理器,任务是建立HTML控件与数据源对象的连接。这就是我们所知道的绑定,可以通过设置某些HTML控件的DATASRC和DATAFLD属性来实现。下面将对这些内容进行讨论,并示范如何在浏览器中方便地使用数据。

10.2.3 支持RDS的浏览器
要知道RDS是微软的技术,因此只能在微软的浏览器上工作。实际上,只有在IE 4.0或更高版本的浏览器中才完全支持RDS。
当编写依赖于RDS的应用程序时,需要注意访问应用程序的客户的RDS版本可能与服务器端有所不同。举例来说,IE 4中的是RDS 1.5版本,而IE 5、Office 2000和Visual Studio 6中的则是RDS 2.0版本。有两种方法可以处理这种兼容性问题:
· 确保所有用户已经升级到RDS的最新版本。如果客户运行的是Windows 2000,那么已经在运行最新版本的RDS了。否则,可以从网址www.microsoft.com/data处下载。RDS 2.5版本是目前最新的随同Windows 2000一起发布的版本,同时也是一个可单独下载的软件包。
· 当连接到数据源时,指定数据工厂的模式。这可以指定使用的是哪一个版本的RDS组件,后面将介绍这方面的一个例子。

10.2.4 数据源对象
数据源对象是一个存储和管理客户端数据的客户端对象。因为这是使用RDS最简单的一种方式,首先研究一下这些对象。
这里有几个不同的数据源对象,每一个都针对不同类型的数据:
· 表格数据控件(Tabular Data Control,TDC),用于处理表格形式或分隔形式的文本文件。
· RDS数据控件,用于连接OLE DB数据存储,能够指定连接到哪个数据存储,以及返回哪些数据。
· Java数据库连接器,这是一个通过Java数据库控件(Java DataBase Control,JDBC)连接到数据存储的Java小程序。这里我们不想讨论JDBC,因为它并不提供其他控件无法实现的功能。
· 微软的HTML(MSHTML)数据源对象用HTML标记数据,并把它作为数据源。
· XML数据源对象使用XML数据,用于结构化的或任意结构的XML。
选用哪一种数据源对象取决于你想做什么,以及数据从哪里来。如果需要向客户提供少量的数据,并且不允许用户修改数据,那么表格数据控件(TDC)可能会比较适合。这种数据源是一个文本文件,不需要任何数据库,因此编辑起来比较简单。对于从数据库中取出数据并且可能需要更新的情况,RDS数据控件是最合适的。而对于许多新数据源,会发现此时需要使用XML数据控件。这实际依赖于所使用的Web应用程序的类型,以及用户所需的功能。
我们将依次介绍这些数据控件,一旦了解了如何用它们把数据传送到客户端,将会介绍如何使用这些数据。
1.  表格数据控件
表格数据控件(Tabular Data Control,TDC)是最简单的数据源对象,主要用于少量的只读数据,特别是那些从不改变或很少修改的,不需要从客户端进行更新的静态数据。例如,表格数据控件能提供一个网页内的菜单项或链接的列表。
通过在HTML代码中使用<OBJECT>标记可以创建一个表格数据控件。参数DataURL可以指定包含文本数据的文件名。
<OBJECT CLASSID="clsid:333C7BC4-460F-11D0-BC04-0080C7055A83"
              ID="dsoAuthors" WIDTH="0" HEIGHT="0">
   <PARAM NAME="DataURL" VALUE="Authors.csv">
</OBJECT>
TDC只读取表格中的数据或标记为表格形式的数据,例如,可以处理逗号分隔形式的数据(Comma Separated Value, CSV),类似于下面的数据:
"172-32-1176","White","Bob","408 496-7223"
"219-46-8915","Green","Marjorie","415 986-7020"
"238-95-7766","Carson","Cheryl","415 548-7723"
"267-41-2394","O'Leary","Michael","408 286-2428"
"274-80-9391","Straight","Dean","415 834-2919"
"341-22-1782","Smith","Meander","913 843-0462"
"409-56-7008","Bennet","Abraham","415 658-9932"
TDC也可以自由定义。除了DataURL外,TDC还有16个参数,可以通过设置OBJECT标记的参数项或编写脚本代码来配置这些参数。参数的说明如表10-1所示:


下面是使用参数创建TDC的一个例子。
<OBJECT CLASSID="clsid:333C7BC4-460F-11D0-BC04-0080C7055A83"
                     ID="dsoAuthors" WIDTH="0" HEIGHT="0">
   <PARAM NAME="DataURL" VALUE="Authors.csv">
</OBJECT>
也可以在客户端脚本中获取数据,下面的例子显示了给TDC加载数据的JScript脚本。
function fillTDC()
{
       dsoAuthors.dataURL = 'authors.csv';
       dsoAuthors.Reset();
}
如果改变了TDC的DataURL参数,必须使用Reset方法,这样才能使新的URL起作用。当介绍数据绑定时,会更详细地讨论如何使用它。Reset方法是TDC唯一的一个方法。
2.  RDS数据控件
RDS数据控件能够访问一般的数据存储,而不是平面文件。它通常用于连接SQL数据库以从表、查询或存储过程获取数据。与TDC不同,RDS数据控件允许更新数据。在本章稍后通过示例说明如何进行数据更新。
类似于TDC,可以用HTML脚本中的OBJECT标记来创建一个RDS数据控件,并以类似的方式设置其属性。
<OBJECT CLASSID='clsid:BD96C556-65A3-11D0-983A-00C04FC29E33"
                     ID="dsoAuthors" WIDTH="0" HEIGHT="0">
       <PARAM NAME="Connect" VALUE="Connection String">
       <PARAM NAME="Server" VALUE="Server Name">
       <PARAM NAME="SQL" VALUE="Query Text">
</OBJECT>
同样,注意定制数据控件时参数的使用方法。上面的例子显示了最常见的设置方法。和TDC一样,还有很多其他可以设置的参数,如表10-2所示:
表10-2  RDS数据控件的参数及说明


异步执行是指在后台检索数据,可以在全部数据返回之前在Web页面上使用已经得到的数据。虽然可能需要的是全部的数据,但异步工作至少可提前开始处理数据。也可让用户先看到某些内容,这使得Web站点看上去响应能力更强。
与TDC类似,RDS数据控件可以通过设置OBJECT标记的参数或编写代码来设置其属性。下面举一个例子:
<OBJECT CLASSID="clsid:BD96C556-65A3-11D0-983A-00C04FC29E33"
              ID="dsoAuthors" WIDTH="0" HEIGHT="0">
       <PARAM NAME="Connect" VALUE="DSN=pubs">
       <PARAM NAME="Server" VALUE="W2000">
       <PARAM NAME="SQL" VALUE="SELECT * FROM Authors">
</OBJECT>
等效于:
<OBJECT CLASSID="clsid:BD96C556-65A3-11D0-983A-00C04FC29E33"
              ID="dsoAuthors" WIDTH="0" HEIGHT="0">
</OBJECT>

<SCRIPT LANGUAGE=JScript>

function window.onload()
{
       dsoAuthors.Connect = "DSN=pubs";
       dsoAuthors.Server = "W2000";
       dsoAuthors.SQL = "SELECT * FROM Authors";
       dsoAuthors.Refresh();
}
</SCRIPT>
这里为Connect参数使用了一个DSN,因为这非常适合该页面,但也可以是任何有效的ADO连接字符串。
URL是ADO 2.5版提供的新特性,允许使用一个文件作为数据源。该文件可以有两种格式:一种是用Recordset.Save方法保存的记录集;另一种是一个ASP页面,它创建一个记录集,然后将其保存在一个流中。代码如下:
<OBJECT CLASSID="clsid:BD96C556-65A3-11D0-983A-00C04FC29E33"
              ID="dsoAuthors" WIDTH="0" HEIGHT="0">
       <PARAM NAME="URL" VALUE="DataPage.asp">
</OBJECT>
文件DataPage.asp包含以下VBScript代码:
<%
       Dim rsData
       Set rsData = Server.CreateObject("ADODB.Recordset")
       rsData.Open "SELECT * FROM Authors", strConn
       rsData.Save Response, adPersistXML
       rsData.Close
       Set rsData = Nothing
%>
这只是创建了一个记录集,然后用Save方法将记录集以XML格式保存到Response对象中。在ADO的早期版本中,只能将记录集存为物理文件,而ADO 2.5版本能够直接将其存为流。这个ASP页面的结果就是XML格式的记录集。下一章将研究关于流和XML数据的所有主题。
使用URL属性优于使用Connect和SQL属性,其最大优点是:在用户可以看到的网页中不会出现连接的细节。考虑下面的对象定义:
<OBJECT CLASSID="clsid: BD96C556-65A3-11D0-983A-00C04FC29E33"
              ID="dsoAuthors" WIDTH="0" HIGHT="0">
       <PARAM NAME="Connect" VALUE="DSN=pubs">
       <PARAM NAME="Server" VALUE="W2000">
       <PARAM NAME="SQL" VALUE="SELECT * FROM Authors">
</OBJECT>
第一行显示了连接的细节。此时能够看到DSN为pubs,并且我们选择了authors表的全部列。这无疑为电脑黑客进入Web站点提供了潜在的路径,因为他们知道了服务器的名称以及数据库的一些细节。现在,考虑一下使用URL属性的情况:
<OBJECT CLASSID="clsid: BD96C556-65A3-11D0-983A-00C04FC29E33"
              ID="dsoAuthors" WIDTH="0" HIGHT="0">
       <PARAM NAME="URL" VALUE="DataPage.asp">
</OBJECT>
现在,用户所见到的是一个ASP网页的URL地址,没有任何有关服务器和数据库的详细信息。
使用CONNECT/SQL属性的方法,用户可以清楚地见到连接的细节,而使用URL所见的却是数据。从这一点上来说,消除了一个安全问题。
在脚本中设置RDS数据控件的属性时,必须使用Refesh方法,如下所示:
<SCRIPT LANGUAGE=JScript>

function window.onload()
{
       dsoAuthors.URL="DataPage.asp";
       dosAuthors.Refresh();
}
</SCRIPT>
这将强迫数据控件使用新的属性值,并重新从数据提供者那里检索数据。除了Refresh方法外,RDS数据控件还有许多其他方法,如表10-3所示:
表10-3  RDS数据控件的方法及说明

在本章后面,会见到大多数方法的使用情况。
3.  MSHTML数据控件
微软HTML(MSHTML)数据控件比较特别的地方在于:MSHTML是IE的一个组成部分,并能提供一个基于HTML文档的数据源。虽然本质上MSHTML并不是为数据存储使用的一种格式,但如果确实有许多包含某些数据格式的HTML网页,MSHTML可能会变得较为有用。
使用这个控件的代码如下所示:
<OBJECT ID="dsoAuthors" DATA="Authors.html" HIGHT="0" WIDTH="0">
</OBJECT>
为了能使用这个控件,必须为HTML标记指定ID属性,因为正是ID属性确定了字段的名称。例如:
<DIV ID="au_id">172-32-1176</DIV>
<SPAN ID="au_lname">White</SPAN>
<H1 ID="au_fname">Bob</H1>
<PRE ID="au_id">213-46-8915</PRE>
<H2 ID="au_lname">Green</H2>
<H1 ID="au_fname">Cheryl</H1>
读者会注意到这看起来不太漂亮。是的,但正是这样才可以说明HTML标记的名称是无关紧要的,ID才是重要的。使用MSHTML DSO解析时,上面的HTML脚本将会产生两行数据,每一行有三个字段。最后会得到类似于表10-4的数据:
表10-4  HTML脚本产生的数据

字段是由ID属性确定的。如果一个标记的ID与现有的ID相同,那么这个标记的数据将成为新的一行,否则在相同的行中创建一个新的字段。
与已经讨论过的数据控件类似,MSHTML数据控件有一个Recordset属性,这也是该控件的唯一的一个属性。MSHTML数据控件没有方法。
4.  XML数据控件
我们已经知道了一种将XML数据放入RDS控件的方法,即使用RDS数据控件和URL属性从ASP文件中获取XML数据。另外一种方法是使用XML Data Island(XML数据岛),这需要使用XML标记。在这里简要地提一下这个问题,因为在下一章会讨论处理XML数据的细节。
<XML>标记是一个与数据控件功能相似的浏览器HTML标记。在许多情况下与使用一个RDS数据控件类似,但该标记是为处理XML数据而特别设计的。使用的方式有二种。
第一种是使用SRC属性来指定数据的位置。
<XML ID="dsoAuthors" SRC="Authors.xml"></XML>
这表示使用文件Authors.xml作为数据源。
另外,也可在标记中嵌入XML。
<XML ID="dsoAuthors">
  <Authors>
       <Author>
              <au_id>172-32-1176</au_id>
              <au_lname>White</au_lname>
              <au_fname>Johnson</au_fname>
              <phone>408 496-7223</phone>
              <contract>True</contract>
       </Author>
       <Author>
              <au_id>213-46-8915</au_id>
              <au_lname>Green</au_lname>
              <au_fname>Marjorie</au_fname>
              <phone>415 986-7020</phone>
              <contract>True</contract>
       </Author>
  </Authors>
</XML>
我们将在下一章详细讨论XML数据控件。

10.2.5 数据绑定
迄今为止,已经可以用几个不同的RDS数据控件将数据送到客户端,但还没有介绍当数据到达客户端后,如何处理数据。实际上,这些数据控件负责的是数据的存储及管理,并不真正地显示数据。因此,问题在于如何将数据从数据控件中取出,并将其提供给HTML元素,使用户能够见到数据。
使用客户端数据最简单的方法是将数据与HTML标记绑定。绑定就是在HTML元素和数据控件之间建立一种联系。数据控件主要负责管理数据,并为HTML元素提供数据,而HTML元素则将数据显示在屏幕上。
为了将数据源与HTML元素绑定,需要设置两个属性:
· DATASRC,确定包含数据的数据控件。在数据源名称前总是要加一个“#”。
· DATAFLD,确定绑定数据控件中的哪个字段。这些字段是数据控件管理的数据中的列名。因此对于一个数据库,就是表中的列名。
例如:
<OBJECT CLASSID="clsid: BD96C556-65A3-11D0-983A-00C04FC29E33"
              ID="dsoAuthors" WIDTH="0" HIGHT="0">
       <PARAM NAME="URL" VALUE="DataPage.asp">
</OBJECT>

<DIV DATASRC="#dsoAuthors" DATAFLD="au_fname"></DIV>
<DIV DATASCR="#dosAuthors" DATAFLD="au_lname"></DIV>
这里,dsoAuthors是一个标准的RDS数据控件。我们创建了两个DIV元素,并通过设置属性DATASRC指向先前定义的数据控件。然后设置属性DATAFLD为字段名,在本例中为au_fname和au_lname。这就是数据绑定的全部过程。其结果如图10-2所示:

需要记住一个重要事情是文本输出(Johnson和White)根本没有在HTML脚本中出现。实际上HTML只由以上显示的内容组成。
因此,数据绑定就是数据控件管理远程数据源的数据,同时HTML元素使用该数据并将其显示在屏幕上的能力。
除此之外,HTML元素还有第三个属性:DATAFORMATAS,可以是HTML或TEXT,表示如何格式化字段中的数据。缺省为TEXT,但如果需要HTML格式的数据,可以通过数据绑定将其格式化,例如下面的文本文件。
Description,Image
The main Wrox logo,<IMG SRC="logos/WroxLogo.gif">
The Wrox Conferences logo,<IMG SRC="logos/WroxConferencesLogo.gif">
The ASPToday logo,<IMG SRC="logos/ASPTodayLogo.gif">
这是TDC的源文件,并且包含两个字段,第一个是说明,第二个是显示某些图像的HTML文本。现在把它和一个HTML表格进行绑定。
<TABLE ID="tblData" DATASRC="#dsoLogos">
  <THEAD>
   <TR>
    <TD>Description</TD>
    <TD>Image</TD>
   </TR>
  </THEAD>
  <TBODY>
   <TR>
    <TD><SPAN DATAFLD="Description"></SPAN></TD>
    <TD><SPAN DATAFLD="Image"></SPAN></TD>
   </TR>
  </TBODY>
</TABLE>
这里不必为数据绑定担心,本例介绍的是表格数据绑定,下面将详细讨论这方面的内容。在这里使用是因为能较好地说明格式化数据。
在浏览器中打开它,将会看到图10-3所示的结果:

可以看到数据文件中的三行数据全部显示在浏览器中,但是HTML作为文本显示。为了见到HTML格式的数据,需要使用属性DATAFORMATAS。
<TD><SPAN DATAFLD="Description"></SPAN></TD>
<TD><SPAN DATAFLD="Image" DATAFORMATAS="HTML"></SPAN></TD>
此时在浏览器打开它,会得到一个效果较好的HTML页面,如图10-4所示:

将第二个字段格式化为HTML文档,这一事实说明了字段任何HTML标记都可以解释成为HTML文档。因此,IMG标记变为真正的图像,而源文件中并不包含任何IMG标记,只有绑定的数据。
可以为任一数据源中的字段使用这种格式,任何HTML标记都会被解释。这对于那些允许用户输入格式化文本的情形是比较有利的。
1.  支持数据绑定的元素
在上面的例子,使用了<SPAN>、<DIV>和<TABLE>标记来绑定数据,但并不是所有的HTML元素都支持数据绑定。表10-5详细列举了这些元素,表中列是:
· HTML元素定义支持数据绑定的元素。
· 绑定属性定义绑定到数据的HTML元素的属性。例如上面的DIV标记,绑定的数据就放在innerText属性中。如果使用A标记,并将其绑定到一个字段,那么数据将会放在href属性中。
· 可否更新数据指出元素中的绑定数据是否能被更新。
· 可否表格绑定指出该元素是否允许绑定子元素。稍后会讨论这个内容。· 可否作为HTML显示指出数据是否能格式化为HTML文档。
    表10-5 支持数据绑定的HTML元素

2.  单个记录绑定
单个记录绑定用于只显示单行数据的情况。例如,考虑下面的代码:
ID:                 <SPAN DATASRC="#dsoData" DATAFLD="au_id"></SPAN><BR>
First Name:     <SPAN DATASRC="#dsoData" DATAFLD="au_fname"></SPAN><BR>
Last Name:     <SPAN DATASRC="#dsoData" DATAFLD="au_lname"></SPAN><BR>
Phone:            <SPAN DATASRC="#dsoData" DATAFLD="phone"></SPAN><BR>
Address:         <SPAN DATASRC="#dsoData" DATAFLD="address"></SPAN><BR>
City:        <SPAN DATASRC="#dsoData" DATAFLD="city"></SPAN><BR>
State:             <SPAN DATASRC="#dsoData" DATAFLD="state"></SPAN><BR>
Zip:                <SPAN DATASRC="#dsoData" DATAFLD="zip"></SPAN><BR>
Contact:         <SPAN DATASRC="#dsoData" DATAFLD="contract"></SPAN><BR>
使用单个记录绑定时,每一个绑定的HTML元素都要确定数据源(DATASRC)和绑定的字段(DATAFLD)。
以上数据绑定的结果如图10-5所示:

作为一个结果来说,这已经满足要求了,但由于在HTML文档中忽略了空格,所以数据排列得不整齐。数据绑定使我们易于得到数据,但看上去不太美观。一个好方法是使用表格来对齐数据。
<TABLE ID="tblData">
  <TR><TD>ID:</TD>
<TD><SPAN DATASRC="#dsoData" DATAFLD="au_id"></SPAN></TD></TR>
  <TR><TD>First Name:</TD>
<TD><SPAN DATASRC="#dsoData" DATAFLD="au_fname"></SPAN></TD></TR>
  <TR><TD>Last Name:</TD>
<TD><SPAN DATASRC="#dsoData" DATAFLD="au_lname"></SPAN></TD></TR>
  <TR><TD>Phone:</TD>
<TD><SPAN DATASRC="#dsoData" DATAFLD="phone"></SPAN></TD></TR>
  <TR><TD>Address:</TD>
<TD><SPAN DATASRC="#dsoData" DATAFLD="address"></SPAN></TD></TR>
  <TR><TD>City:</TD>
<TD><SPAN DATASRC="#dsoData" DATAFLD="city"></SPAN></TD></TR>
  <TR><TD>State:</TD>
<TD><SPAN DATASRC="#dsoData" DATAFLD="state"></SPAN></TD></TR>
  <TR><TD>Zip:</TD>
<TD><SPAN DATASRC="#dsoData" DATAFLD="zip"></SPAN></TD></TR>
  <TR><TD>Contact:</TD>
<TD><SPAN DATASRC="#dsoData" DATAFLD="contract"></SPAN></TD></TR>
</TABLE>
这个HTML文档虽然不容易阅读,但却提供了一个较好的显示结果,如图10-6所示:

注意,这个例子只显示了使用SPAN元素来存放数据。如果想编辑数据,那么可以使用INPUT元素来实现。例如:
<TABLE ID="tblData">
  <TR><TD>ID:</TD>
<TD>
<INPUT TYPE="TEXT" DATASRC="#dsoData" DATAFLD="au_id"></INPUT>
</TD>
</TR>
...
       </TABLE>
这里使用了一个TEXT类型的INPUT元素。注意,数据绑定几乎是相同的,仅仅是HTML元素不同。结果如图10-7所示:

数据导航
除非能得到其他记录,否则只显示单条记录并不理想。幸运的是数据控件有一个Recordset属性,它是实际的含有数据的ADO记录集。回顾第8章,应该记得记录集有移动记录的方法:
· MoveFirst。
· MoveNext。
· MovePrevious。
· MoveLast。
举一个例子,假定想在HTML页面中增加一些按钮以获得记录导航的能力,如图10-8所示:

可以用如下代码创建按钮:
<button id="cmdFirst" title="First Record"
    onclick="dsoData.recordset.MoveFirst()"> |< </button>

<button id="cmdPrevious" title="Previous Record"
    onclick="if (!dsoData.recordset.BOF) dsoData.recordset.MovePrevious()">
     < </button>

<button id="cmdNext" title="Next Record"
    onclick="if (!dsoData.recordset.EOF) dsoData.recordset.MoveNext()">
     > </button>

<button id="cmdLast" title="Last Record"
    onclick="dsoData.recordset.MoveLast()"> >| </button>
这些代码仅仅利用了记录集中移动记录的方法。移到第一条和最后一条记录实现想来相当容易。只需记住数据控件有一个Recordset属性,由于该属性是一个对象,所以有其自己的方法。因此,代码可以写为:
dsoData.recordset.MoveFirst()
以上代码只是简单地调用数据控件管理的记录集的MoveFirst方法。
移到上一条和下一条记录的代码看上去有一点技巧,但也很简单。
if (!dsoData.recordset.BOF)
dsoData.recordset.MovePrevious()
以上是向后移动记录的方法,只需在执行MovePrevious方法之前,判断一下记录集的BOF属性,以确定当前记录不在记录集的开始位置。
3.  表格绑定
表格绑定不同于单个记录绑定,因为不只是为对齐数据而使用表格。在表格绑定中把数据绑定到了TABLE元素,能够一次看到多条记录,如图10-9所示:

这甚至比单个记录绑定更容易,实现表格绑定需要使用表格的DATASRC属性,然后使用DATAFLD属性绑定表格元素。这样就将表格与数据控件绑定起来,每一个表格单元绑定到单独的字段。
然而,看一下能够被绑定的HTML元素的列表,会发现表格单元元素(TD)并不在其中。因为这个原因,一般为只读的表格使用SPAN或DIV标记,而对于可编辑的表格则使用INPUT标记。例如,图10-9中的表格是用下列代码创建的:
<TABLE ID="tblData" DATASRC="#dsoData">
  <THEAD>
   <TR>
    <TD>au_id</TD>
    <TD>au_fname</TD>
    <TD>au_lname</TD>
    <TD>phone</TD>
    <TD>address</TD>
    <TD>city</TD>
    <TD>state</TD>
    <TD>zip</TD>
    <TD>contract</TD>
   </TR>
  </THEAD>
  <TBODY>
   <TR>
    <TD><INPUT TYPE="TEXT" DATAFLD="au_id"></INPUT></TD>
    <TD><INPUT TYPE="TEXT" DATAFLD="au_fname"></INPUT></TD>
    <TD><INPUT TYPE="TEXT" DATAFLD="au_lname"></INPUT></TD>
    <TD><INPUT TYPE="TEXT" DATAFLD="phone"></INPUT></TD>
    <TD><INPUT TYPE="TEXT" DATAFLD="address"></INPUT></TD>
    <TD><INPUT TYPE="TEXT" DATAFLD="city"></INPUT></TD>
    <TD><INPUT TYPE="TEXT" DATAFLD="state"></INPUT></TD>
    <TD><INPUT TYPE="TEXT" DATAFLD="zip"></INPUT></TD>
    <TD><INPUT TYPE="TEXT" DATAFLD="contract"></INPUT></TD>
   </TR>
  </TBODY>
</TABLE>
TABLE元素还有另外一个用于数据绑定的属性:DATAPAGESIZE,决定了在表格中可以显示的记录数。
<TABLE ID="tblData" DATASRC="#dsoData" DATAPAGESIZE="10">
在上面的例子中,表格一次只能含有10条记录。记录集的移动方法在这里不起作用,因为表格限制了可见的记录,所以必须使用表格的两个方法,如下所示:
<button id="cmdPreviousPage" title="Previous Page"
       onclick="tblData.PreviousPage()">Previous Page</button>
<button id="cmdNextPage" title="Next Page"
       onclick="tblData.NextPage()">Next Page</button>
4.  动态绑定
到目前为止,所有的例子都只显示了一个固定的记录集,绑定的字段在设计期间已经创建。但看起来大量的代码不能重用,特别是在Web应用程序正给用户带来越来越强的功能的情况下,这种方式缺乏开发程序的灵活性。
解决这个难题的方法是根据数据控件中的数据动态创建表中的字段。实际上这也比较容易,依赖于客户端的脚本程序。那么,假定让用户在表authors和publishers中进行选择,如图10-10所示:

现在我们并不真想绑定两个表的所有字段,因为这会变得难以维护。如果源数据的结构改变了,或者想增加另一个表,情况将会怎样?处理这种情况的方法就是创建一个虚表,在运行期间动态地创建和绑定字段。
首先,创建数据控件。
<OBJECT CLASSID="clsid:BD96C556-65A3-11D0-983A-00C04FC29E33"
        ID="dsoData" HEIGHT="0" WIDTH="0"
        ondatasetcomplete="createCells()">
</OBJECT>
这是RDS数据控件,与前面例子唯一不同的是这里没有设置参数,代码中也是如此。唯一增加的是设置了一个在数据控件读完数据后运行的函数。
接下来,需要创建两个按钮来确定数据。
<BUTTON ID="cmdAuthors"
onclick="resetData('authors')">authors</BUTTON>
<BUTTON ID="cmdPublishers"
onclick="resetData('publishers')">publishers</BUTTON>
下面创建虚表。
<TABLE ID="tblData" border=1>
  <THEAD><TR></TR></THEAD>
  <TBODY><TR></TR></TBODY>
</TABLE>
这充当了模板的作用。注意,表格中还没有单元格。这是因为并不知道数据有多少个字段,所以也将在运行期间创建它们。
现在编写JScript代码。首先看一下resetData函数,该函数设置数据控件的属性并加载数据。
function resetData(sTable)
{
    // reset the data
    dsoData.Connect = 'Provider=SQLOLEDB; Data Source=' +
                      '<%= Request.ServerVariables("SERVER_NAME") %>' +
                      '; Initial Catalog=pubs; User ID=sa; Password=';
    dsoData.Server = 'http://<%= Request.ServerVariables("SERVER_NAME") %>';
    dsoData.SQL = 'SELECT * FROM ' + sTable;
    dsoData.Refresh();
}

虽然这看起来比使用参数更复杂一些,但是仍然比较简单。别忘了参数名是如何映射到属性的?这里所做的就是设置那些属性,然后调用Refresh方法更新数据控件。看上去,这可能比以前的例子更糟糕,因为在代码中只有不多的ASP,也只是简单地在属性中填入Web服务器的名字。但使用该方法可以在不修改代码的情况下将此ASP页面从一个服务器移到另一个服务器。作为数据源的表名可以通过选择适当的按钮而传给函数。
一旦加载了数据,将触发数据控件的ondatasetcomplete事件,运行createCells函数。
function createCells()
{
    var fldF;
    var tblCell;

    // delete what's there already
    deleteCells();

    // now create the new cells
    for (fldF = new Enumerator(dsoData.recordset.Fields);
         !fldF.atEnd(); fldF.moveNext())
    {
        // create a new cell for the heading
        tblCell = tblData.rows[0].insertCell();
        tblCell.innerHTML = '<B>' + fldF.item().name + '</B>';

        // create a new cell for the body
        tblCell = tblData.rows[1].insertCell();
        tblCell.innerHTML = '<INPUT TYPE="TEXT" DATAFLD="' +
                            fldF.item().name + '"></INPUT>';
    }

    // now bind to the data source
    tblData.dataSrc = '#dsoData';
}
这同样也很简单。首先删除了现有的表格单元格(马上会介绍这个函数),然后遍历记录集的字段。在行头为每个字段创建一个新单元格(这个表格只有两行:第一行,即第0行,是表头;第二行,即第1行,是表体)。表格单元创建完后,将innerHTML属性设为对应的字段名。在表体中创建新单元格的过程类似,但此时使用innerHTML元件保存绑定到数据字段的INPUT标记。当所有的字段都完成这样的操作后,这个表就与数据控件绑定了。
因为这个页面允许在两个不同的数据集之间进行切换,所以需要先删除现有的数据。
function deleteCells()
{
    var iCell;
    var iCells;

    // unbind the table
    tblData.dataSrc = '';

    // delete existing cells
    iCells = tblData.rows[0].cells.length
    for (iCell = 0; iCell < iCells; ++iCell)
    {
        tblData.rows[0].deleteCell();
        tblData.rows[1].deleteCell();
    }
}
这个子程序只是对表解除绑定,然后在表格中遍历所有的单元格并删除它们。等到上述程序执行完毕,表格就只剩下空的表头和表体行。
这是一个用RDS和一些DHTML实现的简单例子。可以容易地把其加到一个ASP包含文件中,并把该文件放到任何应用程序中,即使数据源不改变也可使用这种方法。
这个例子的全部代码——文件RDSDynamicBinding.asp以及类似的其他类型的数据控件例子,可以在Wrox站点上找到。

10.2.6 更新数据
迄今为止,仅学习了在客户端如何取到数据,但还没有涉及如何更新客户端数据,和将其送回服务器。别忘了,记录集是断开连接的,那么如何更新数据呢?对数据所做的任何修改只是数据控件中本地记录的一部分,因此为了更新服务器必须发一条特殊的指令。然而这并不需做什么复杂的工作,因为RDS数据控件有两个方法,允许我们要么取消最近对数据所做的任何修改,要么将所有修改送到服务器。
为了方便用户,可以为此创建一些按钮。
<BUTTON ID="cmdCancelAll" TITLE="Abandon All Chnages"
       ONCLICK="dsoData.CnacelUpdate()">Cnacel</BUTTON>

<BUTTON ID="cmdUpdateAll" TITLE="Save All Changes"
       ONCLICK="dsoData.SubmitChanges()">Save</BUTTON>
SubmitChanges方法只将那些改动过的记录送回服务器,而CancelUpdate方法则取消在本地记录集上所做的任何修改。
更新和取消更新操作并不是唯一所需的。如果想增加新的记录或删除一条现有的记录,怎么办?可以使用记录集的AddNew和Delete方法。这将增加或删除记录集中的记录,然后在发送SubmitChanges命令后,服务器上的数据就可以被更新。
<BUTTON ID="cmdDelete" TITLE="Delete This Record"
       ONCLICK="dsoData.recordset.Delete()">Delete</BUTTON>

<BUTTON ID="cmdAddNew" TITLE="Add New Record"
       ONCLICK="dsoData.recordset.AddNew()">Add</BUTTON>
    1. 解决冲突的方法
    由于与数据源断开连接,可能会碰到有关冲突的问题。例如在更新一条记录并将其保存到数据存储的时候,有人也修改了这条记录时,会发生什么情况? SubmitChanges方法已经提供了相应的处理冲突的方法,如果发生冲突,那么该方法将产生一个错误。
    在调用SubmitChanges方法期间,只要其中一条记录更新失败,那么所有的记录更新都会失败。这保证了原始数据不会被部分更新。可以遍历记录集,并检测记录的Status属性来告诉用户哪一条记录更新失败了。例如,最好调用自己的updateData函数,而不只是在命令按钮中调用SubmitChanges方法。

    此时,我们知道已经发生了一个错误,但并不知道是哪一个错误,因此必须重新同步当前数据与数据存储中的数据。使用adResyncUnderlyingValues确保只有字段的UnderlyingValues属性被数据存储中的值覆盖,也就是说所做的修改是安全的(记住,修改的内容保存在Value属性中)。可以在后面的代码中比较当前的值与数据库中的值。

    Status可以是不同值的组合,详见附录。例子代码( RDSConflicts.asp )中有一个将这些值转换为描述性字符串的函数。
    我们知道记录有某些形式的冲突,但无法确切地知道为什么或哪一个字段引起了冲突。因此需要遍历字段检测它们的值。

    这就是UnderlyingVaule属性发挥作用的地方。
    字段有三种值:
    Vaule代表新值,即经过修改的字段值。
    UnderlyingVaule代表数据存储中存储的字段值。
    OriginalVaule代表从数据存储读取后,但还没有修改之前的字段值。
    这意味着UnderlyingVaule会保存其他用户修改过的值,而OriginalValue是字段原有的值。因此比较两者之值,如果不同,则说明字段已经被另外的用户修改了。
    可以利用所有这些错误信息来创建一个表格以显示是否确实发生错误。例子(RDSConflicts.asp)产生的输出结果如图1 0 - 11所示。

    这里可以见到三种不同的值。原始值是Johnson。然后,在另一个窗口(如SQL Server Query Analyzer)中将值改为Johnson。在浏览器窗口,利用RDS将这个值改为Andy,并按下Save All Changes按钮。Resync命令将数据库中的值取出并写入UnderlyingVaule属性。我也对Lastname列做了相似的修改。
    使用这种方法,可以看到每一个发生变化的字段的值。由于SubmitChanges方法可以处理多个字段,读者可能希望为这个表增加额外的列以显示ID字段,这样就可以看到是哪一个字段更新失败了。

 
 
  
评论】【加入收藏夹】【 】【打印】【关闭
※ 相关链接
 ·ASP学习:远程注册自己的组件  (2005-04-02)
 ·用Flash远程调用增强J2EE表示层  (2005-04-02)
 ·ASP远程脚本调用  (2005-03-12)
 ·Win2k IIS 远程执行命令漏洞  (2005-03-12)
 ·开发连接远程SQL Server 的ASP程  (2005-03-12)
 ·Remote Scripting进阶教程---远程  (2005-03-12)
 ·利用ASP远程注册DLL的方法  (2005-03-12)
 ·利用ASP远程注册DLL的方法  (2005-03-12)
 ·远程获取内容,并将内容存在本地  (2005-03-12)
 ·基于Java&XML技术构建植物病虫害  (2005-03-12)

   栏目导行
  PHP编程
  ASP编程
  ASP.NET编程
  JAVA编程
   站点最新
·致合作伙伴的欢迎信
·媒体报道
·帝国软件合作伙伴计划协议
·DiscuzX2.5会员整合通行证发布
·帝国CMS 7.0版本功能建议收集
·帝国网站管理系统2012年授权购买说
·PHPWind8.7会员整合通行证发布
·[官方插件]帝国CMS-访问统计插件
·[官方插件]帝国CMS-sitemap插件
·[官方插件]帝国CMS内容页评论AJAX分
   类别最新
·在ASP中使用数据库
·使用ASP脚本技术
·通过启动脚本来感受ASP的力量
·学习使用ASP对象和组件
·解析asp的脚本语言
·初看ASP-针对初学者
·ASP开发10条经验总结
·ASP之对象总结
·ASP与数据库应用(给初学者)
·关于学习ASP和编程的28个观点
 
关于帝国 | 广告服务 | 联系我们 | 程序开发 | 网站地图 | 留言板 帝国网站管理系统