当前位置: 首页 > 编程语言 > vfp > 正文

用vfp与sql server构建Client/Server应用程序(远程视图)(3)

时间:2007-05-09

可更新视图(Updateble views)

上面我们讲解了“怎样通过远程视图从服务器中把数据读取过来”,接着我们要讲解怎样操作远程视图光标,当然我们不会在这里讨论一些Visual FoxPro数据集的普通操作,这里我们只讲解远程视图的数据更新。

当远程视图被打开,用户就可以使用Visual FoxPro的命令与函数作光标进行各种操作,例如查询、新添数据、删除记录、修改记录等,后三者都会使数据发生变动,远程视图有着自动分析各种变动并把变动的结果发送到后端数据库更新数据源的功能。

顺便提一下,Visual FoxPro 在数据更新这方面的的能力是非常强大的——如果一个视图是由多个数据源表连接而成,Visual FoxPro 能够自动分析客户端数据变动所对应的数据源信息,“分门别类”对远程数据数据进行的更新。现在一些非常著名的数据引擎中都不具备这个功能,详细情况请看本站文集中的《Visual FoxPro 漫谈》一文。

键值栏、可更新字段、SQL 更新开关

我们可以通过“视图设计器”制作可更新的远程视图(当然可以用它设计上文提到的那些远程视图),如图 7。为了设定一个远程视图为可更新视图,在视图设计器中您必须多做三件事情(比不可更新的远程视图):

  1. 设定键值栏。系统之所以能够知道你变动了视图中的那一笔记录并在数据源中作出相应的变动,就是依靠键值来判断的。可以这样理解:键值就是能够惟一标识表中数据记录的标记。键值是不可以重复的。设想一下在一个员工表中,您把性别设定为键值,并修改某一员工的姓名,然后发送更新,这会造成什么结果(事实上Visual FoxPro会报告键值不唯一的错误,我们假设Visual FoxPro不报错):与该被修改姓名的员工具有相同性别的员工的名字都被修改了,很可笑吧!
    一般Visual FoxPro会自动从SQL Server中把键值信息读到,并自动设定键值栏。
    如果没有现成能够唯一标识记录的字段,则可以使用联合字段。

  2. 设定可更新字段。只有那些被设置为可更新的字段,它们的变动才会反映到数据源表中。并不是所有的字段都是可更新字段,例如:在SQL Server中的 带有 Identity 属性的字段(由系统维护其数值,常作为键值)。

  3. 打开“发送SQL更新”选项。很多人在视图设计器中“千辛万苦”的设定了好多信息,但客户端数据变动就是不能发送到后端,原因就是他们忘记了这最最基本的选项。记住:要视图可更新,此项必须设定。


图 7. 视图设计器

我们可以通过DBSETPROP()函数设定以上三个选项:

DBSETPROP("VCustomers.CustomerID", "Field", "KeyField", .T.)
*设定键值栏
DBSETPROP("VCustomers.CustomerID", "Field", "Updatable", .T.)
*设定可更新字段,有很多字段要写,这里省略
DBSETPROP("VCustomers", "View", "SendUpdates", .T.)
*打开“发送 SQL 更新”

在图7中我们还有两项属性没有设定:“使用更新”,“SQL WHERE 子句包括”。

更新方式

“使用更新”的作用就是:告诉Visual FoxPro怎样分解更新操作,也就是一种“更新方式”的选择。举个例子,我们对视图中某一行的字段值做了修改。如果本属性设为“SQL UPDATE”,发送更新时Visual FoxPro会往后端传送一条UPDATE-SQL语句;如果本属性设为“SQL DELETE 然后 UPDATE”,发送更新时Visual FoxPro会往后端传送一条DELETE-SQL语句——删去原来的记录,再传送一条INSERT-SQL语句——把带有新值的记录加入数据源。很容易发现:前一种设定更有效率,但为什么还要有后一种选择呢?原来有一些老式的数据库不支持UPDATE-SQL……对于主流的数据库系统应该不会有这种问题,所以我们在通常情况下选择“SQL UPDATE”。

SQL WHERE 子句包括——更新冲突的检测方式

“更新冲突”是指当某一位使用者在修改某一笔数据时,同一笔数据记录的内容已被其他使用者修改。下图就是一个更新冲突的示意图,红色代表数据源,黑色代表进程一,蓝色代表进程二。


图 8. 更新冲突示意

此设定有四个选项:关键字段,关键字和可更新字段,关键字和已更新字段,关键字和时间戳。

  1. 关键字段:若选择此选项,系统只会检查来源表的键值栏的内容是否被修改。

  2. 关键字和可更新字段:若选择此选项,系统将会检查数据源表的键值栏与可更新的字段内容是否被修改。

  3. 关键字和已更新字段:若选择此选项,系统将会检查数据源表的键值栏与已修改的字段内容是否被修改。这里提请大家注意,大文本对象(Image,text类型的字段)被设定为可更新字段时,不应该使用这种更新冲突检测方案,因为这样对系统消耗太大,事实上Visual FoxPro也不允许你这样做。
    这是最常用检测更新冲突检测方案。

  4. 关键字和时间戳:当SQL SERVER 的任意一笔数据记录的任何字段被更新(新增、删除、修改),系统都会打上一个烙印——时间戳。时间戳是一种全局唯一的二进制字符,千万不要理解为时间日期型的数据。在使用关键字和时间戳更新冲突检测方案时还必须注意,数据源表的时间戳字段必须出现在远程视图中(Visual FoxPro会将其转换成为Character Binary类型)。关键字和时间戳更新冲突检测方案主要用于多人使用的更新冲突的核查。若选择此选项系统将会利用键值栏与时间戳字段来检查数据记录是否已被修改,这一项比上三个选项检查效率更快也更严谨(从理论上讲),因为它的系统负担最小。

为使您更好的理解更新冲突以及更新冲突检测方案,我们把图8结合实例讲解一下。

CREATE SQL VIEW VCustomers ;
REMOTE CONNECTION Northwind SHARE;
AS SELECT CustomerID,CompanyName,Phone FROM Customers
*新建远程视图
DBSETPROP("VCustomers.CustomerID", "Field", "KeyField", .T.)
DBSETPROP("VCustomers.CompanyName", "Field", "Updatable", .T.)
DBSETPROP("VCustomers.Phone", "Field", "Updatable", .T.)
DBSETPROP("VCustomers", "View", "SendUpdates", .T.)
DBSETPROP("VCustomers", "View", "WhereType", 3)
*设定更新冲突解决方案为“关键字和已更新字段”
DBSETPROP("VCustomers", "View", "UpdateType", 1)

*进程一
USE VCustomers
BROWSE
*将指针停留在第一条记录上,即:CustomerID='ALFKI'
REPLACE Phone with '123456'
*离开Visual FoxPro,千万别移动记录指针

进程二
使用 SQL Server 的 Enterprise Manager 打开 Customers表,把指针停在第一条记录上,修改Phone的值为'00000',移动指针到下一条记录。

回到Visual FoxPro,移动指针,您会看到图9:


图 9.更新冲突

按“还原”按钮。试验结束。

仔细想想,您就会明白什么是更新冲突了。

上例中,如果我们设定“关键字”方式检测更新冲突:

DBSETPROP("VCustomers", "View", "WhereType", 1)

其他均按原先步骤进行,您会发现没有更新冲突产生。因为Visual FoxPro仅检测关键字是否变化,这里进程一、二都没有修改关键字,当然不会有更新冲突。

上例中,如果我们设定“关键字和可更新字段”方式检测更新冲突:

DBSETPROP("VCustomers", "View", "WhereType", 2)

其他均按原先步骤进行,这时会有更新冲突产生。因为Visual FoxPro不仅检测关键字是否变化,还要检测所有的可更新字段字段(本例是所有字段)是否发生变化,这里进程二先进程一修改了可更新字段 Phone,进程一当然会有更新冲突发生。

如果使用 SQL Server 的 Profiler 程序您能更好的了解以上内容:


图 10。 SQL Server 的 Profiler 程序

1.使用“关键字段”冲突检测方式,发送更新时,Visual FoxPro 自动生成以下语句在 SQL Server 中执行:

sp_executesql N'UPDATE dbo.Customers SET Phone=@P1 WHERE CustomerID=@P2', N'@P1 nvarchar(24),@P2 varchar(50)', N'123456 ', 'ALFKI'

可见,UPDATE 的 WHERE 子句只包括关键字段:CustomerID。在Visual FoxPro 缓冲中 CustomerID='ALFKI',Visual FoxPro 就以这个值作为数据源是否发生改变的依据。如果 SQL Server执行这条UPDATE语句时找不到CustomerID='ALFKI'的记录(我们认为是其它用户先期修改了CustomerID)——SQL Server 告诉 Visual FoxPro 更新冲突发生了。

2.使用“关键字和可更新字段”冲突检测方式,发送更新时,Visual FoxPro 自动生成以下语句在 SQL Server 中执行:

sp_executesql N'UPDATE dbo.Customers SET Phone=@P1 WHERE CustomerID=@P2 AND CompanyName=@P3 AND Phone=@P4', N'@P1 nvarchar(24),@P2 varchar(50),@P3 nvarchar(40),@P4 nvarchar(24)', N'123456 ', 'ALFKI', N'Alfreds Futterkiste ', N'030-0074321 '

可见,UPDATE 的 WHERE 子句包括关键字段:CustomerID,和所有可更新字段:CompanyName、Phone。Visual FoxPro 缓冲中CustomerID='ALFKI'、CompanyName='Alfreds Futterkiste'、Phone='030-0074321',如果 SQL Server执行这条UPDATE语句时找不到(CustomerID='ALFKI' AND CompanyName='Alfreds Futterkiste' AND Phone='030-0074321')的记录(我们认为是其它用户先期修改了这三者中的任何一个多几个的值)——SQL Server 告诉 Visual FoxPro 更新冲突发生了。

3.使用“关键字和已更新字段”冲突检测方式,发送更新时,Visual FoxPro 自动生成以下语句在 SQL Server 中执行:

sp_executesql N'UPDATE dbo.Customers SET Phone=@P1 WHERE CustomerID=@P2 AND Phone=@P3', N'@P1 nvarchar(24),@P2 varchar(50),@P3 nvarchar(24)', N'123456 ', 'ALFKI', N'030-0074321'

可见,UPDATE 的 WHERE 子句包括关键字段:CustomerID,和所有以经被 Visual FoxPro 更新的字段:Phone。Visual FoxPro 缓冲中CustomerID='ALFKI'、Phone='030-0074321',如果 SQL Server执行这条UPDATE语句时找不到(CustomerID='ALFKI' AND Phone='030-0074321')的记录(我们认为是其它用户先期修改了这两者中的任何一个多几个的值)——SQL Server 告诉 Visual FoxPro 更新冲突发生了。

4.如果希望尝试“关键字和时间戳”冲突检测方式,请在 SQL Server与Visual FoxPro的远程视图中加入TimeStamp字段。发送更新时,Visual FoxPro 自动生成以下语句在 SQL Server 中执行:

UPDATE dbo.Customers SET Phone=N'12345 ' WHERE CustomerID='ALFKI' AND timestamp=0x0000000000000199

可见,UPDATE 的 WHERE 子句包括关键字段:CustomerID,和时间戳字段。Visual FoxPro 缓冲中CustomerID='ALFKI'、时间戳是:0x0000000000000199,如果 SQL Server执行这条UPDATE语句时找不到(CustomerID='ALFKI' AND timestamp=0x0000000000000199')的记录(我们认为是其它用户先期修改了数据源表中该行的数据,只要有任何变化,时间戳就会自动更改)——SQL Server 告诉 Visual FoxPro 更新冲突发生了。

如果您还没有理解更新冲突——这很正常,请往下看。