可更新視圖(Updateble views)
上面我們講解了“怎樣通過遠程視圖從伺服器中把資料讀取過來”,接著我們要講解怎樣操作遠程視圖游標,當然我們不會在這裡討論一些Visual FoxPro資料集的普通操作,這裡我們只講解遠程視圖的資料更新。
當遠程視圖被開啟,使用者就可以使用Visual FoxPro的命令與函數作游標進行各種操作,例如查詢、新添資料、刪除記錄、修改記錄等,後三者都會使資料發生變動,遠程視圖有著自動分析各種變動並把變動的結果發送到後端資料庫更新資料來源的功能。
順便提一下,Visual FoxPro 在資料更新這方面的的能力是非常強大的——如果一個視圖是由多個資料來源表串連而成,Visual FoxPro 能夠自動分析用戶端資料變動所對應的資料來源資訊,“分門別類”對遠端資料資料進行的更新。現在一些非常著名的資料引擎中都不具備這個功能,詳細情況請看本站文集中的《Visual FoxPro 漫談》一文。
索引值欄、可更新欄位、SQL 更新開關
我們可以通過“視圖設計器”製作可更新的遠程視圖(當然可以用它設計上文提到的那些遠程視圖),如圖 7。為了設定一個遠程視圖為可更新視圖,在視圖設計器中您必須多做三件事情(比不可更新的遠程視圖):
-
設定索引值欄。系統之所以能夠知道你變動了視圖中的那一筆記錄並在資料來源中作出相應的變動,就是依靠索引值來判斷的。可以這樣理解:索引值就是能夠惟一標識表中資料記錄的標記。索引值是不可以重複的。設想一下在一個員工表中,您把性別設定為索引值,並修改某一員工的姓名,然後發送更新,這會造成什麼結果(事實上Visual FoxPro會報告索引值不唯一的錯誤,我們假設Visual FoxPro不報錯):與該被修改姓名的員工具有相同性別的員工的名字都被修改了,很可笑吧!
一般Visual FoxPro會自動從SQL Server中把索引值資訊讀到,並自動設定索引值欄。
如果沒有現成能夠唯一標識記錄的欄位,則可以使用聯合欄位。
-
設定可更新欄位。只有那些被設定為可更新的欄位,它們的變動才會反映到資料來源表中。並不是所有的欄位都是可更新欄位,例如:在SQL Server中的 帶有 Identity 屬性的欄位(由系統維護其數值,常作為索引值)。
-
開啟“發送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. 更新衝突示意
此設定有四個選項:關鍵字段,關鍵字和可更新欄位,關鍵字和已更新欄位,關鍵字和時間戳記。
-
關鍵字段:若選擇此選項,系統只會檢查來源表的索引值欄的內容是否被修改。
-
關鍵字和可更新欄位:若選擇此選項,系統將會檢查資料來源表的索引值欄與可更新的欄位內容是否被修改。
-
關鍵字和已更新欄位:若選擇此選項,系統將會檢查資料來源表的索引值欄與已修改的欄位內容是否被修改。這裡提請大家注意,大文字物件(Image,text類型的欄位)被設定為可更新欄位時,不應該使用這種更新衝突檢測方案,因為這樣對系統消耗太大,事實上Visual FoxPro也不允許你這樣做。
這是最常用檢測更新衝突檢測方案。
-
關鍵字和時間戳記:當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 更新衝突發生了。
如果您還沒有理解更新衝突——這很正常,請往下看。