深入CursorAdapter(一)
来源:优易学  2011-12-9 18:18:26   【优易学:中国教育考试门户网】   资料下载   IT书店

  CursorAdapter 类是 VFP 8 中最重要的新功能之一,因为它提供了一种简单易用、接口统一的访问远程数据源方式。在这个月的文章里,Dung Hennig 将向你展示 CursorAdapter 及它的工作方式。下个月,我们将再学习一些高级的用法。

  正文:越来越多的 VFP 程序员开始把他们的数据储存到象 SQL Server 或者 Oracle 这样的 VFP 表以外的数据仓库中去了。有许多原因导致了这种情况,包括 VFP 表的脆弱性(不管是想象中的还是确实如此)、安全性、数据库的容量、以及通用性的标准等等。MicroSoft 已经在每一个版本中都使得访问非VFP数据更加的简单,为了鼓励这种风气,它甚至在 VFP 7 光盘中自带了 MSDE(Microsoft Data Engine,SQL Server 的一个免费、简装版)。

  不过,访问一个后台数据库从来就比使用 VFP 表要麻烦一些,而你可以使用的机制则多得吓人:

  ×× 远程视图,它基于 ODBC 连接;

  ×× SQL Passthrough (SPT) 函数,例如 SQLCONNECT()、SQLEXEC() 和 SQLDISCONNECT(),它们也基于 ODBC 连接;

  ×× ActiveX Data Objects ,简称 ADO,它提供了一个对各种数据库引擎的 OLE Provider 的一个面对对象访问方式;

  ×× XML,它是一个轻量级的、平台无关的数据传输机制。

  如果你曾经用这些机制上工作过,有一件事情你可能已经注意到了:它们中的每一种都各不相同。这样的话,你就必须一个个的学过来,还要把一个已有的应用程序从一种机制转换到另一种机制,这可不是一件简单的工作。

  由于有了一个新的基础类 CursorAdapter,在 VFP 8 中访问远程数据要比过去的版本中简单的多。以我之见,CursorAdapter 是 VFP 8 最重要的新功能之一。我认为它最棒的地方是:

  ×× 使用 ODBC、ADO、XML 变得非常容易,即时你不熟悉这些技术。

  ×× 不管你选择了哪种远程数据源机制,它都提供一种统一的访问接口。

  ×× 从一种机制转换到另一种机制变得非常的轻松。

  这里是上面的最后一个观点的例子。假设你有一个使用 CursorAdapter 通过 ODBC 来访问 SQL Server 数据的应用程序,由于某些原因你想要改成使用 ADO 了。对于这种情况,你只需要改动 CursorAdapter 的 DataSourceType 属性、并改变对后台数据库的连接,就全部完成了。你的应用程序中的其它部分不需要知道也不需要关心这些事情;它们看到的只是同一个 Cursor 而不管使用了哪一种机制。

  属性

  我们先从查看 CursorAdapter 的属性、事件和方法开始来学习它。这里不会讨论所有的属性,只谈一下最重要的那些。

  DataSourceType

  这个属性是最重要的:它决定了这个类的表现,以及要在其它一些属性中要怎么设置。可用的选项有“Native”——意思是使用 VFP 表——或者是 "ODBC"、"ADO" 或 "XML" ,表示你要选用的访问远程数据源的方式。

  DataSource

  这是访问数据的手段。当 DataSourceType 被设置成“Native”或者“XML”的时候,VFP会忽略这个属性的设置。对于ODBC,请把这个属性设置为一个有效的 ODBC 连接句柄(这意味着你要自己管理连接了)。在ADO的情况下,DataSource 必须是一个 ADO RecordSet,而且它的 ActiveConnection 对象必须被设置为一个打开的 ADO Connection 对象(你又要自己管理这些了)。

  UseDEDataSource

  如果这个属性被设置成了 .T.(默认是 .F.),你可以不管它的 DataSourceType 和 DataSource 属性,因为 CursorAdapter 将使用 DataEnvironment 的属性来代替( VFP 8 给 DataEnvironment 也增加了 DataSourceType 和 DataSource 属性)。举例来说,当你想让在一个数据环境中的所有 CursorAdapters 斗使用同一个 ODBC 连接的时候,就可以把它设置为 .T.。

  SelectCmd

  除了 XML 的情况以外,这是一个用来取得数据的 SQL Select 命令。在 XML 的情况下,它可以或者是一个能够被转换为一个 Cursor 的有效 XML 字符串(使用内部的 XMLTOCURSOR() 调用),或者是一个能够返回一个有效的 XML 字符串的表达式。

  CursorSchema

  这个属性里保存的是 Cursor 的数据结构,格式就像你在用 CREATE CURSOR 命令的时候用的那样。这是一个例子:CUST_ID C(6), COMPANY C(30), CONTACT C(30), CITY C(25)。尽管不设置这个属性而让 CursorAdapter 在自己建立 Cursor 去决定这个结构也是可以的,不过如果你自己输入的话,它会工作的更好。如果 CursorSchema 是空的或者不正确,那么当你打开一个表单的数据环境的时候,就会要么弹出一个错误,要么就不能通过从 CursorAdapter 中拖放字段到表单上来建立控件。幸运的是,VFP 自带的 CursorAdapter 生成器可以为你填充这个属性。

  AllowDelete、AllowInsert、AllowUpdate 和 SendUpdates

  这些属性的默认值是 .T.,它们决定了是否可以删除、插入和更新和改动是否要被发送到数据源。

  KeyFieldList、 Tables、 UpdatableFieldList、和 UpdateNameList

  这些属性的用途跟 CURSORSETPROP() 中用到的那些参数的用途是一样的,如果你想让 VFP 自动将对 Cursor 的改动提交到数据源,这些属性就是必须的。

  ×× KeyFieldList 是一个用逗号分隔的字段列表(不带别名),这些字段组成 Cursor 的主关键字。Tables 是一个用逗号分隔的表名列表。
  ×× UpdatableFieldList 是一个用逗号分隔的可以被更新的字段名列表(不带别名)。
  ×× UpdateNameList 是一个用逗号分隔的列表,它用来让 Cursor 中的字段名与在表中的字段名相匹配。UpdateNameList 的格式就像 这样:CURSORFIELDNAME1 TABLE.FIELDNAME1、CURSORFIELDNAME2 TABLE.FIELDNAME2 等等。注意:如果 UpdatableFieldList 不包含表的主键字段的名称(比如说你不想让用户可以更新这个字段),在 UpdateNameList 还是必须要有这个字段,否则就不能更新。

  Cmd、*CmdDataSource 和 *CmdDataSourceType

  如果你想指定让 VFP 怎样去删除、插入和更新数据源中的记录,你可以给这些属性设置相应的值——注意,* 的位置是 Delete、Insert 或者 Update。

  CursorFill(UseCursorSchema, NoData, Options, Source)

  这个方法建立 Cursor,并用来自数据源的数据填充这个 Cursor(你也可以给 NoData 参数传递一个 .T.以建立一个空的 Cursor),给第一个参数传递 .T. 来使用定义在 CursorSchema 中的游标数据结构,或者传递 .F. 来根据数据源中的结构建立一个相应的结构。MULTILOCKS 必须被设置成 ON,否则这个方法将执行失败。如果 CursorFill 由于某些原因执行失败,它不会发生一个错误而是返回 .F.,不过你还是可以用 AERROR() 来检查发生了什么错误(准备苦苦挖掘吧!通常你得到的错误信息都不足以告诉你究竟问题在哪里)。

  CursorRefresh()

  这个方法类似于 Requery() 函数:它刷新 Cursor 的内容。

  Before*() 和 After*()

  CursorAdapter 的几乎每个方法和事件都有一套 before 和 After 开头的“hook”事件(hook这个词中文没有很好的对应,勉强把它翻译成“挂钩”还不如不翻),这样你就可以自定义 CursorAdapter 的行为特性了。例如,你可以在 AfterCursorFill 中为 Cursor 建立索引。在 Before 系列事件中你可以返回一个 .F. 来防止触发被 hook 的事件发生(类似于数据库事件)。

  示例

  这里是一个示例来自附带的示例文件 (CursorAdapterExample.prg),它用于从 SQL Server 自带的 Northwind 数据库的 Customers 表中取得巴西客户的某几个字段数据。产生的 Cursor 是可更新的,所以如果你对 Cursor 中的数据做了某些改动,然后再次运行程序,你会看到刚才所作的改动已经被保存在后台数据库中了。
  local lcConnString,
  loCursor as CursorAdapter,
  laErrors[1] lcConnString = 'driver=SQL Server;server=(local);' +
  'database=Northwind;uid=sa;pwd=;trusted_connection=no'
  * 把这里的密码改成你自己的数据库中密码

  loCursor = createobject('CursorAdapter')
  with loCursor
  .Alias = 'Customers'
  .DataSourceType = 'ODBC'
  .DataSource = sqlstringconnect(lcConnString)
  .SelectCmd = "select CUSTOMERID, " +
  "COMPANYNAME, CONTACTNAME from CUSTOMERS " +
  "where COUNTRY = 'Brazil'"
  .KeyFieldList = 'CUSTOMERID'
  .Tables = 'CUSTOMERS'
  .UpdatableFieldList = 'CUSTOMERID, COMPANYNAME, ' +
  'CONTACTNAME'
  .UpdateNameList =
  'CUSTOMERID CUSTOMERS.CUSTOMERID, ' +
  'COMPANYNAME CUSTOMERS.COMPANYNAME, ' +
  'CONTACTNAME CUSTOMERS.CONTACTNAME'
  if .CursorFill()
  browse
  else
  aerror(laErrors)
  messagebox(laErrors[2])
  endif
  .CursorFill()
  endwith

  数据环境和表单的增强

  为了支持新的 CursorAdapter 类,对表单和数据环境类也做了一些增强。
  首先,象我前面提到过的那样,DataEnvironment 类现在有了 DataSource 和 DataSourceType 属性。不过它自己并不使用这些属性,而是给那些在这个数据环境中的那些 UseDEDataSource 被设置成了 .T. 的 CursorAdapter 使用的。其次,现在你可以使用类设计器来可视化的建立 DataEnvironment 的子类了(哇!)。
  而对于表单,你可以通过设置新的 DEClass 和 DEClassLibrary 属性来指定使用一个 DataEnvironment 的子类了。不过这么做一定要趁早,因为在这么干了以后,原来的数据环境中所有已经做好的东西(Cursor、代码等等)都会丢失,还好系统会先警告你。表单的一个很酷的新功能是它的 BindControls 属性——把这个属性设置为.F.就可以让表单在 INIT 的时候不对控件进行数据绑定,而只有当 BindControls 被设置为 .T. 的时候才会这样。这个功能好在哪里呢?你曾经多少次诅咒过这样的情况:参数必须被传递给表单的INIT事件,而INIT事件却要等到所有的控件已经初始化并已经绑定到它们的数据源了以后才会被触发?要是你想向该表单传递一个参数来告诉表单打开哪个表或者其它会影响 ControlSources 的事情的时候该怎么办?这个新的属性让这些事情变得象打个瞌睡那么容易。
  

[1] [2] 下一页

责任编辑:小草

文章搜索:
 相关文章
热点资讯
资讯快报
热门课程培训