您现在的位置: 中国男护士网 >> 考试频道 >> 计算机等级 >> 二级辅导 >> VFP >> 辅导 >> 正文    
  深入CursorAdapter(二) 【注册男护士专用博客】          

深入CursorAdapter(二)

www.nanhushi.com     佚名   不详 

  考试大计算机等级站整理:

  在 VFP8 中新增的 CursorAdapter 基类提供一个统一、易用的数据接口。Doug Hennig 在这个月的文章中演示了怎样使用 CursorAdapter 来访问本地数据和 ODBC、ADO和XML这样的远程数据——讨论了使用各种数据源相应的特殊要求和实现途径。

  正文:
  如我在上一篇文章中所提到的那样,在VFP8中一个最重要的、也是最精彩的新功能是新的 CursorAdapter 基类。在那篇文章中,我们研究了一下 CursorAdapter 的属性、事件和方法,并讨论了它相对于远程视图、SQL PassThrough(SPT)、ADO和XML的优势。
  在开始使用 CursorAdapter 之前,你需要根据要访问的是本地数据还是通过ODBC、ADO或者XML的远程数据源的不同,注意这个类所相应的不同的特殊要求。这个月的文章就讲述了使用各种数据源的细节。

  使用本地数据源

  ×××××××
  尽管我们很清楚 CursorAdapter 是试图用来标准化和简化对非VFP数据的访问方式的,不过你还是可以把它当作是 Cursor 的代替品用它来访问VFP数据:只要把它的 DataSourceType 属性设置成 "Native"。为什么要这么做呢?因为你的应用程序将来可能会需要升迁——那时候你就可以把 DataSourceType 属性设置成其它几个选项之一(当然可能还需要修改其它几个属性,例如设置连接信息等等),就能轻松的切换到另一种数据库引擎,例如SQL Server。
  当 DataSourceType 属性的设置为 "Native" 的时候,VFP 会忽略它的 DataSource 属性。SelectCmd 属性必须是一个 SQL Select 语句(而不是一个 USE 命令或表达式),这就意味着你用 CursorAdapter 不是直接操作本地表而是操作一个类似于本地视图那样的东西。你还必须确保VFP能够找到出现在那个 Select 语句中的任何表,因此,如果这些表不在当前路径中,那么你就需要设置一下路径或者打开这些表所属的数据库。此外,就跟用视图一样,如果你想让这个 Cursor 是可更新的,你还必须设置好那些与更新相关的属性(KeyFieldList、Tables、UpdatableFieldlist 和 UpdateNameList)。
  下面的例子(文章附件 NativeExample.prg)会用 VFP 示例数据库中的 Customer 表建立一个可更新的 Cursor:
  local loCursor as CursorAdapter, laErrors[1]
  Open database (_samples + 'data\testdata')
  with loCursor
  .Alias = 'customercursor'
  .DataSourceType = 'Native'
  .SelectCmd = "Select CUST_ID, COMPANY, CONTACT FROM CUSTOMER " +
  "WHERE COUNTRY = 'Brazil'"
  .KeyFieldList = 'CUST_ID'
  .Tables = 'CUSTOMER'
  .UpdatableFieldList = 'CUST_ID, COMPANY, CONTACT'
  .UpdateNamelist = 'CUST_ID CUSTOMER.CUST_ID, '+
  'COMPANY CUSTOMER.COMPANY, CONTACT CUSTOMER.CONTACT'

  if .CursorFill()
  browse
  tableupdate(1)
  else
  aerror(laErrors)
  messagebox(laErrors[2])
  endif .CursorFill()
  endwith
  close databases all

  使用 ODBC
  ×××××
  ODBC 是 DataSourceType 属性四种设置中最简单的一种。把 DataSource 设置为一个打开了的 ODBC 连接句柄、设置一下常用的属性、然后调用 CursorFill 来取得数据。如果你设好了 KeyFieldList、Tables、UpdatableFieldList 和 UpdateNameList 属性,VFP 会自动把你对数据的任何改动转换成相应的 UPDATE、INSERT、和 DELETE 语句来把改动提交到后台数据源。如果你想用的是一个存储过程,那么要相应的设置 *Cmd、*CmdDataSource 和 *CmdDataSourceType 属性(* 代表 “Delete”、“Insert”或“Update”)。
  这里是附件 ODBCExample.prg 中的一个例子,它调用 Sql Server 自带的 NorthWind 数据库中的 CustOrderHist 存储过程来取得销售给某个客户的单位产品总数。
  local lcConnString, loCursor as CursorAdapter, laErrors[1]
  lcConnString = 'driver=SQL Server;server=(local);database=Northwind;uid=sa;pwd=;"+
  "trusted_connection=no'

  ** 把上面连接字符串中的密码改成你的SQL Server 登录的密码
  loCursor = createobject('CursorAdapter')
  with loCursor
  .Alias = 'Customerhistory'
  .DataSourceType = 'ODBC'
  .DataSource = SQLStringConnect(lcConnString)
  .SelectCmd = "exec CustOrderhist 'ALFKI'"

  if .CursorFill()
  browse
  else
  aerror(laErrors)
  messagebox(laErrors[2])
  endif .CursorFill()
  endwith

  使用 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 模板的内容如下:
  SELECT *
  FROM Customers
  WHERE CustomerID = @customerid
  FOR XML AUTO

  把这个文件放在用于 Northwind 数据库的一个虚拟目录中(参见补充文档《设置 SQL Server 2000 XML 访问》以了解更多关于为 SQL Server 2000 设置 IIS 的内容、以及这篇文章所需要的特殊细节。)
  SendNWXML 的内容看起来与 GetNWCustomers 类似,除了它接收的参数是一个 DiffGram,然后它把这个 DiffGram 加载到一个 MSXML2.DOMDocumnet 对象中,并把这个对象传递给 Web Server,该 Web Server 会通过 SQLXML 把这个对象传递给 SQL Server 2000 去处理。
  lparameters tcDiffGram
  local loDOM as MSXML2.DOMdocument.
  loXML as MSXML2.XMLHTTP
  loDOM = createobject('MSXML2.DOMdocument.#39;)
  loDOM.async = .F.
  loDOM.loadXML(tcDiffGram)
  loXML = createobject('MSXML2.XMLHTTP')
  loXML.open('POST', ' http://localhost/northwind/', .F.)
  loXML.setRequestHeader('Content-type', 'text/xml')
  loXML.send(loDOM)
  运行 XMLExample.prg 来看看它是怎么工作的。你将会在 Browse 窗口中看到一台记录(客户 ALFKI)。试着改动几个字段的值,然后关闭这个窗口,再运行 PRG 一遍。你会看到你的改动已经被写入到后台数据源中了。
  总结
  ××
  尽管 CursorAdapter 基类提供了一种对远程数据源的统一的结构,而不管你使用的是 ODBC、ADO还是XML——但是,根据你选择的数据访问机制的不同,对 CursorAdapter 的设置也有一些区别。这些区别取决于数据访问机制的本身。
  下个月,我将通过建立一些可重用的数据类、并讨论怎样在报表中使用 CursorAdapter 来结束这个系列的专题。
  补充文档:
  《设置 SQL Server 2000 XML 访问》
  为了能够在一个浏览器或者其它 HTTP 客户端用一个 URL 来访问 SQL Server 2000,你需要做一些工作。首先,你需要从 MSDN 网站( http://msdn.microsoft.com——查询一下“SQLXML”,然后选择下载)去下载和安装 SQLXML 3.0。
  接着,你需要设置一个 IIS 虚拟目录。步骤如下:从开始菜单|程序|SQLXML 3.0文件夹中单击“Configure IIS Support(设置 IIS 支持)”。展开你的服务器节点,选择要使用的 Web 站点,然后单击鼠标右键,选择“新建|虚拟目录”,在出现的对话框的“常规”页中输入虚拟目录的名称和它的物理路径。在这里,我们使用“Northwind”作为虚拟目录名、“NorthwindTemplates”作为物理路径。使用 Windows 资源管理器在你的系统上的什么地方建立这个物理目录,然后给它建一个名为 “Template”的子目录(稍后我们将会用到这个子目录)。把附件中的两个模板文件 GetAllCustomers.xml 和 CustomersByID.xml 拷贝到这个子目录中。
  在“安全”页中,输入访问 SQL Server 的相应的信息,例如用户名和密码或者你想采用的特定的验证机制。在“数据源”页上,选择 SQL Server,如果需要的话,还要选择要使用的数据库。在这里我们选择 Northwind 数据库。在“设置”页上选择希望的设置,至少要选上“允许模板查询”和“允许 Post”。
  在“虚拟名称”页中,从类型组合框中选择“模板”,并输入一个虚拟名称(在这里我们使用“template”)和物理路径(它应该是虚拟目录的一个子目录,在这里就是 "Template"子目录),这是使用模板的需要。好,单击“确定”。
  现在我们测试一下是否每样东西都设置正确了,我们将通过使用你拷贝到 Template 子目录中去得 GetAllCustomers.xml来访问 SQL Server。它的内容如下:
  SELECT *
  FROM Customers
  FOR XML AUTO
  为了测试的目的,打开你的浏览器,并输入这个URL: http://localhost/northwind/template/getallcustomers.xml,你就会在浏览器中看到XML形式的 Northwind Customers 表的内容了。

 

文章录入:杜斌    责任编辑:杜斌 
  • 上一篇文章:

  • 下一篇文章:
  • 【字体: 】【发表评论】【加入收藏】【告诉好友】【打印此文】【关闭窗口
     

    联 系 信 息
    QQ:88236621
    电话:15853773350
    E-Mail:malenurse@163.com
    免费发布招聘信息
    做中国最专业男护士门户网站
    最 新 热 门
    最 新 推 荐
    相 关 文 章
    没有相关文章
    专 题 栏 目

      网友评论:(只显示最新10条。评论内容只代表网友观点,与本站立场无关!)                            【进男护士社区逛逛】
    姓 名:
    * 游客填写  ·注册用户 ·忘记密码
    主 页:

    评 分:
    1分 2分 3分 4分 5分
    评论内容:
  • 请遵守《互联网电子公告服务管理规定》及中华人民共和国其他各项有关法律法规。
  • 严禁发表危害国家安全、损害国家利益、破坏民族团结、破坏国家宗教政策、破坏社会稳定、侮辱、诽谤、教唆、淫秽等内容的评论 。
  • 用户需对自己在使用本站服务过程中的行为承担法律责任(直接或间接导致的)。
  • 本站管理员有权保留或删除评论内容。
  • 评论内容只代表网友个人观点,与本网站立场无关。