End Function %> 这仅仅是调用一个存储过程,从而得到书的类型,同时创建一个SELECT列表。上述代码的缺点在于每次调用该函数都必须访问数据库。因此,重新修改这个函数。 <% Function BookTypes()
Dim rsBookTypes Dim strQuote Dim strList
' See if the list is in the cache strList = Application("BookTypes") If strList = "" Then ' Not cached, so build up list and cache it strQuote = Chr(34)
Set rsBookTypes = Server.CreateObject ("ADODB.Recordset")
' Get the book types rsBookTypes.Open "usp_BookTypes", strConn
9.4.1 使用数据整形 应用数据整形必须: · 使用MSDataShape OLEDB提供者。 · 使用一种特殊的整形语言,它是SQL的一种扩充,允许构造层次。 尽管使用新的提供者,连接字符串的实际改变不会太大。这是因为仍然需要从某处获取数据。因此,可以这么做: Provider=MSDataShape; Data Provider=SQLOLEDB; Data Source=... 这里用MSDataShape作为提供者,而正常的Provider变为Data Provider,而连接字符串的剩余部分保持不变。 为数据整形创建连接字符串的简便方法是从创建正规的连接字符串开始,然后附加到数据整形块的最后。例如,考虑以下正规的连接字符串。 strConn = "Provider=SQLOLEDB; Data Source=Kanga; " & _ " Initial Catalog=pubs; User Id=sa; Password=" 可以像下面这样为数据整形提供者创建连接字符串。 strConn = "Provider=MSDataShape; Data " & strConn 这将提供者设置为MSDataShape,而Data Provider成为实际的数据源。初始的连接字符串已经包含了"Provider= ",所以为了获得正确的连接细节,只须前面加上Data。 1. 整形语言 整形语言有其自己的语法,但这里我们不打算涉及其构造,它已包含在ADO文献中。大多数情况下会采用以下命令。 SHAPE {parent command} [AS parent alias] APPEND ({child command} [AS child alias] RELATE parent_column TO child_column) [AS parent_column_name] 要理解这一点,最简单的方法是看一个实例,以Publishers和Titles为例。 SHAPE {SELECT * FROM publishers} APPEND ({SELECT * FROM Titles} RELATE Pub_ID TO PubID) AS rsTitles 第一行是父记录集,第二行则是子记录集。第三行指明了关联父、子记录集的两个字段。这个例子中两个表都有一个名为Pub_ID的字段(出版社ID字段)。这个命令返回一个包含出版社的记录集,在记录集的最后又附加了一个含有子记录集的新列(类型为adChapter)。该列名为AS子句给出,在本例中是rsTitles。 adChapter类型只是说明了该字段含有一个子记录集。我个人认为,adChild或adRecordset更合适。 通过遍历Fields集合,可以很容易看到父记录集的字段的情况。对于上面的SHAPE命令,得到图9-9所示的结果:
图9-9 执行SHAPE命令后的结果 访问子记录集 现在,我们有了一个子记录集,它是另一个记录集的一个字段,那么如何访问这个子记录集呢?很简单,可以使用字段的Value属性来建立另一个记录集。 Set rsTitles = rsPublishers("rsTitles").Value 可以遍历父记录集,对应于每个父记录可以得到一个子记录集。下面的代码能实现这一点。通常以包含文件、变量声明开始。 <!-- #INCLUDE FILE="../Include/Connection.asp" --> <% Dim rsPublishers Dim fldF Dim strShapeConn Dim strShape
Set rsPublishers = Server.CreateObject ("ADODB.Recordset") 现在创建连接字符串。 ' Create the provider command strShapeConn = "Provider=MSDataShape; Data " & strConn 接下来,输入实际的整形命令。这将创建一个包含出版社的父记录集和一个含有书名的子记录集。 ' now the shape command strShape = "SHAPE {SELECT * FROM Publishers}" & _ " APPEND ({SELECT * FROM Titles}" & _ " RELATE Pub_ID TO Pub_ID) AS rsTitles" 然后正常打开记录集。 ' Open the shaped recordset rsPublishers.Open strShape, strShapeConn 像正常的记录集一样,能够遍历记录。 ' loop through the publishers Response.Write "<UL>" While Not rsPublishers.EOF Response.Write "<LI>" & rsPublishers("pub_name") 为了访问子记录集,设置一个变量来指向那个包含子记录集的字段的Value值。本例中该变量为rsTitles。 ' now the titles Response.Write "<UL>" Set rsTitles = rsPublishers("rsTitles").Value 变量rsTitles在这里是个记录集,其作用同普通的记录集相同。因此,可以遍历该记录集的值,该值只包含与父出版者匹配的书名。 ' loop through the titles While Not rsTitles.EOF Response.Write "<LI>" & rsTitles("title") rsTitles.MoveNext Wend Response.Write "</UL>"
' move to the next publisher rsPublishers.MoveNext Wend Response.Write "</UL>"
rsPublishers.Close Set rsPublishers = Nothing Set rsTitles = Nothing %> 于是得到一份令人满意的出版社与书名的列表,如图9-10所示:
图9-10 整形后的书名列表 用一些DHTML代码和一些额外的标记,就能轻松地隐藏起书名,并且只有选择出版社时才显示相应的书名。 2. 多个子记录集 如果对于每个记录集仅能有一个子记录集,那么数据整形就不够完善。但数据整形是极其灵活的。例如可以使用下面的程序来为出版社引用标题和雇员。 SHAPE {select * from publishers} APPEND ({select * from titles} RELATE pub_id TO pub_id) AS rsTitles, ({select * from employee} RELATE pub_id To pub_id) AS rsEmployees 只需在APPEND子句后加上其他子记录集,就能得到图9-11的结果:
图9-11 多个子记录集的结果 访问子记录集的方法并没有改变,仍旧可以用列的Value属性访问子记录集。只是此时有两个子记录集,因此需要使用两个变量。 Set rsTitles = rsPublishers("rsTitles").Value
Set rsEmployees = rsPublishers("rsEmployees").Value 3. 孙代记录集 在子记录集自身还包含子记录集的情况下,可能会出现孙代记录集。例如: SHAPE {SELECT * FROM Publishers} APPEND (( SHAPE {SELECT * FROM Titles} APPEND ({SELECT * FROM Sales} RELATE Title_ID TO Title_ID) AS rsSales) RELATE Pub_ID TO Pub_ID) AS rsTitles 在第一个APPEND子句内是另一个SHAPE命令,而不是一个SELECT语句。与多个子记录集的例子相似,访问孙代记录集的方法是相同的。 Set rsTitles = rsPublishers("rsTitles").Value
Set rsSales = rsTitles("rsSales").Value 对子和孙记录集的深度没有理论上的限制,但也不可能建立多于三级或四级的子记录集。
9.4.2 性能 数据整形不会自动改善性能,但正确使用时可以改善性能。重要的是记住其工作方式: · 对于SHAPE命令中的SELECT语句,将完全取出表中的数据。SQL语句并没有得到任何优化。这样,如果在父表中加入WHERE子句来限制父记录集的记录数,仍能得到所有的子记录集。例如: SHAPE {SELECT * FROM Publishers WHERE State='CA'} APPEND ({SELECT * FROM Titles} RELATE Pub_ID TO Pub_ID) AS rsTitles APPEND语句返回所有的标题,并不仅限于加州(CA)的出版社。记住,这不是SQL JOIN语句。在加州的出版社以及所有的标题都被提取了,这样就完成了数据整形。 · 可以使用存储过程,这会提高一点性能。然而,如果使用一个参数化的存储过程产生子记录集,那么每次访问子记录集时,这个存储过程都会执行。这意味着,子记录集不在前端代码中编程产生,而是只包含存在存储过程产生的那么记录。不足之处是增加了服务器的工作,但这样却能保证数据是最新的,因为每次需要时就从数据库中提取数据。 在下一章当我们着眼于客户端数据时,会看到更多有关经过整形的记录集的介绍。