![]() ![]() |
|
深入CursorAdapter(二) | |
作者:佚名 文章来源:不详 点击数 更新时间:2008/6/24 9:12:08 文章录入:杜斌 责任编辑:杜斌 | |
|
|
考试大计算机等级站整理: 在 VFP8 中新增的 CursorAdapter 基类提供一个统一、易用的数据接口。Doug Hennig 在这个月的文章中演示了怎样使用 CursorAdapter 来访问本地数据和 ODBC、ADO和XML这样的远程数据——讨论了使用各种数据源相应的特殊要求和实现途径。 正文: 使用本地数据源 ××××××× if .CursorFill() 使用 ODBC ** 把上面连接字符串中的密码改成你的SQL Server 登录的密码 if .CursorFill() 使用 ADO ×××× 与使用 ODBC 相比,使用 ADO 要多一些需要操心的事情: ×× DataSource 必须被设置成一个 ADO RecordSet,而且这个 RecordSet 的 ActiveConnection 属性需要被设置成一个打开了的 ADO Connection 对象。 ×× 如果你想要使用一个参数化查询(与下载全部数据相比,这可能是更常用的方式),你必须把一个 ADO Command 对象作为第四个参数传递给 CursorFill 方法,而且这个 Command 对象的 ActiveConnection 属性需要被设置成一个打开了的 ADO Connection 对象。VFP 会为你照顾好填充 Command 对象的参数化集合的事情(它通过分析 SelectCmd 来找出参数),不过参数所包含的值当然还是必须在有效取值范围内的。 ×× 在数据环境中只有一个使用了 ADO 的 CursorAdapter 这样的情况是比较简单的:如果需要的话,你可以把 UseDEDataSource 属性设置成 .T.,然后根据你的需要把数据环境的 DataSource 和 DataSourceType 属性设置成 CursorAdapter。不过,如果数据环境中有多个 CursorAdapter 的话,这种办法就无效了。原因是 DataEnvironment.DataSource 所引用的 ADO RecordSet 只能包含一个 CursorAdapter 的数据;当你为第二个 CursorAdapter 调用 CursorFill 方法的时候,会出现 “RecordSet is already open (RecordSet 记录集已经打开)”的错误。所以,如果你的数据环境中有超过一个的 CursorAdapter,你必须要把 UseDEDataSource 设置成 .F.,并自行管理每个 CursorAdapter 的 DataSource 和 DataSourceType 属性(或者你可以使用一个能够管理这种情况的 DataEnvironment 的子类)。 附件 ADOExample.prg 中的示例代码演示了怎样借助一个 ADO Command 对象来取得数据。这个示例还演示了使用 VFP8 中新的结构化错误处理的功能。对 ADO Connection 对象的 Open 方法的调用被封装在一个 TRY...CATCH...ENDTRY 语句中,以捕捉调用这个方法失败的时候将会出现的 COM 错误。 local loConn as ADODB.Connection, loCommand as ADODB.Command, loException as Exception, loCursor as CursorAdapter, lcCountry, laErrors[1] loConn = createobject('ADODB.Connection') with loConn .ConnectionString = 'provider=SQLOLEDB.1;data source=(local);' + 'initial catalog=Northwind;uid=sa;pwd=dhennig;trusted_connection=no' && 把上面连接字符串中的密码改成你的SQL Server 登录的密码 try .Open() catch to loException messagebox(loException.Message) cancel endtry endwith loCommand = createobject('ADODB.Command') loCursor = createobject('CursorAdapter') with loCursor .Alias = 'Customers' .DataSourceType = 'ADO' .DataSource = createobject('ADODB.RecordSet') .SelectCmd = 'select * from customers where country=?lcCountry' lcCountry = 'Brazil' .DataSource.ActiveConnection = loConn loCommand.ActiveConnection = loConn if .CursorFill(.F., .F., 0, loCommand) browse else aerror(laErrors) messagebox(laErrors[2]) endif .CursorFill(.F., .F., 0, loCommand) endwith 使用 XML ×××× 用 CursorAdapter 来操作 XML 需要一些特殊的设置。下面是这些问题: ×× DataSource 属性被忽略; ×× CursorSchema 属性必须被填充好——即使你给 CursorFill 传递的第一个参数是 .F. 也一样——否则将会出错。 ×× SelectCmd 必须被设置成一个表达式,例如一个用户自定义函数(UDF)或者对象方法名,该表达式能够为 Cursor 返回 XML。 ×× 对 Cursor 的改动会被转换成一个 DiffGram,它是“包含着被改动了的字段或者记录,在被改动之前、被改动之后的值”的XML,当需要更新的时候,它被放在 DiffGram 属性中。 ×× 为了把数据更动回写到数据源中去,UpdateCmdDataSourceType 属性必须被设置为“XML”,并且 UpdateCmd 必须被设置成一个能够处理提交更新任务的表达式(象前面一样,这个表达式也是象一个 UDF 或者对象的方法)。你可能会需要把 “This.DiffGram”传递给那个 UDF,这样它就可以把更新提交给后台数据源。 这个 Cursor 所使用的 XML 源文件可能来自各种不同的地方。例如,你可以调用这样一个UDF:它能用 CursorToXML()来把一个VFP Cursor 转换成 XML,并返回结果: use CUSTOMERS cursortoxml('customers', 'lcXML', 1, 8, 0, '1') Return lcXML UDF 可以调用一个 Web Service,这个 Web Service 则返回一个 XML 结果集。这里是一个例子,我建立了一个 Web Service 并注册在我自己的系统上, 而智能感知则为我生成了下面的代码(具体的细节并不重要,它只是演示了一个 Web Service 的例子): loWS = newobject("WSclient', home() + 'ffc\_webservices.vcx') loWS.cWSName = 'dataserver web service' loWS = loWS.SetupClient(' http://localhost/' + 'SQDataServer/dataserver.WSDL', 'dataserver', 'dataserverSoapPort') lcXML = loWS.GetCustomers() Return lcXML 它能够在一个 Web Server 上使用 SQLXML 3.0 去执行一个存储在一个临时文件中的 SQL Server 2000 查询(要了解关于 SQLXML 更多的信息,请访问 http://msdn.microsoft.com并查找 SQLXML)。下面的代码使用一个 MSXML2.XMLHTTP 对象通过 HTTP 从 Northwind 数据库的 Customers 表来取得所有的记录,稍后我们将做更进一步的解释。 local loXML as MSXML2.XMLHTTP loXML = createobject('MSXML2.XMLHTTP') loXML.open('POST', ' http://localhost/northwind/' + 'template/getallcustomers.xml, .F.) loXML.setRequestHeader('Content-type', 'text/xml') loXML.send() return loXML.responseText 处理更新的事情要更复杂一点。数据源必须或者能够接受并处理一个 DiffGram (比如 SQL Server 2000 的情况),或者你必须自己去弄清楚所有的改动、执行一系列的 SQL 语句(UPDATE、INSERT 和 DELETE)去提交更新。 这里是个使用了带 XML 数据源的 CursorAdapter 的例子(XMLExample.prg)。要注意的是:SelectCMD 和 UpdateCMD 都是要调用 UDF 的。在 SelectCMD 的情况中,要返回数据的客户编号被传递给一个叫做 GetNEWustomers 的 UDF,这个我们稍后再提。在 UpdateCmd 的情况中,VFP 把 DiffGram 属性传递给 SendNWXML,这个我们也稍后再提。 local loCustomers as CursorAdapter, laErrors[1] loCustomers = createobject('CursorAdapter') with loCustomers .Alias = 'Customers' .CursorSchema = 'CUSTOMERID C(5), COMPANYNAME C(40), ' + 'CONTACTNAME C(30), CONTACTTITLE C(30), ADDRESS C(60), ' + 'CITY C(15), REGION C(15), POSTALCODE C(10), COUNTRY C(15), ' + 'PHONE C(24), FAX C(24)' .DataSourceType = 'XML' .KeyFieldList = 'CUSTOMERID' .SelectCmd = 'GetNWCustomers([ALFKI])' .Tables = 'CUSTOMERS' .UpdatableFieldList = 'CUSTOMERID, COMPANYNAME, CONTACTNAME, ' + 'CONTACTTITLE, ADDRESS, CITY, REGION, POSTALCODE, COUNTRY, PHONE, FAX' .UpdateCmdDataSourceType = 'XML' .UpdateCmd = 'SendNWXML(This.DiffGram)' .UpdateNameList = 'CUSTOMERID CUSTOMERS.CUSTOMERID, ' + 'COMPANYNAME CUSTOMERS.COMPANYNAME, ' + 'CONTACTNAME CUSTOMERS.CONTACTNAME, ' + 'CONTACTTITLE CUSTOMERS.CONTACTTITLE, ' + 'ADDRESS CUSTOMERS.ADDRESS, ' + 'CITY CUSTOMERS.CITY, ' + 'REGION CUSTOMERS.REGION, ' + 'POSTALCODE CUSTOMERS.POSTALCODE, ' + 'COUNTRY CUSTOMERS.COUNTRY, ' + 'PHONE CUSTOMERS.PHONE, ' + 'FAX CUSTOMERS.FAX' if .CursorFill(.T.) browse else aerror(laErrors) messagebox(laErrors[2]) endif .CursorFill(.T.) endwith 这里是 GetNWCustomers 的代码。它使用了一个 MSXML2.XMLHTTP 对象来访问一个位于一个Web Server 上的名叫 CustomersByID.xml 的 SQL Server 2000 XML 模板,并返回结果。要获取数据的 Customer ID 被作为一个参数传递给这段代码: lparameters tcCustID local loXML as MSXML2.XMLHTTP loXML = createobject('MSXML2.XMLHTTP') loXML.open('POST', " http://localhost/northwind/template/customersbyid.xml?";;; + "customerid=" + tcCustID, .F.) loXML.setRequestHeader('Content-type', 'text/xml') loXML.send() return loXML.responseText 这段代码里引用的名为 CustomersByID.XML 的 XML 模板的内容如下: 把这个文件放在用于 Northwind 数据库的一个虚拟目录中(参见补充文档《设置 SQL Server 2000 XML 访问》以了解更多关于为 SQL Server 2000 设置 IIS 的内容、以及这篇文章所需要的特殊细节。) |
|
![]() ![]() |