VFP 愛用者社區 首頁 VFP 愛用者社區
本討論區為 Visual Foxpro 愛用者經驗交流的地方, 請多多利用"搜尋"的功能, 先查看看有無前例可循, 如果還有不懂的再發問. 部份主題有附加檔案, 須先註冊成為社區居民才可以下載.
 
 常見問題常見問題   搜尋搜尋   會員列表會員列表   會員群組會員群組   會員註冊會員註冊 
 個人資料個人資料   登入檢查您的私人訊息登入檢查您的私人訊息   登入登入 

CursorAdapter 起步 2 (轉貼)

 
發表新主題   回覆主題    VFP 愛用者社區 首頁 -> VFP 討論區
上一篇主題 :: 下一篇主題  
發表人 內容
Ruey



註冊時間: 2003-03-12
文章: 1698
來自: tunglo

第 1 樓

發表發表於: 星期六 十月 11, 2003 12:57 pm    文章主題: CursorAdapter 起步 2 (轉貼) 引言回覆

CursorAdapter 起步 2 [轉帖]
CursorAdapter 起步 之 二:用 CursorAdapter 來取得和更新資料
作者:Dung Hennig
譯者:fbilo
在 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”)。
這堿O附件 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 結果集。這堿O一個例子,我建立了一個 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)去提交更新。
這堿O個使用了帶 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

這堿O 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
這段代碼堣犍峈漲W為 CustomersByID.XML 的 XML 範本的內容如下:
<root xmlns:sql="urn:schemas-microsoft-com:xml-sql">
<sql:header>
<sql:param name="customerid">
</sql:param>
</sql:header>
<sql:query client-side-xml="0">
SELECT *
FROM Customers
WHERE CustomerID = @customerid
FOR XML AUTO
</sql:query>
</root>
把這個檔放在用於 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')
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 站點,然後單擊滑鼠右鍵,選擇 “新建|虛擬目錄”,在出現的對話方塊的“常規”頁中輸入虛擬目錄的名稱和它的物理路徑。在這堙A我們使用“Northwind”作為虛擬目錄名、“NorthwindTemplates”作為物理路徑。使用 Windows 資源管理器在你的系統上的什麼地方建立這個物理目錄,然後給它建一個名為 “Template”的子目錄(稍後我們將會用到這個子目錄)。把附件中的兩個範本檔 GetAllCustomers.xml 和 CustomersByID.xml 拷貝到這個子目錄中。
在“安全”頁中,輸入訪問 SQL Server 的相應的資訊,例如用戶名和密碼或者你想採用的特定的驗證機制。在“資料源”頁上,選擇 SQL Server,如果需要的話,還要選擇要使用的資料庫。在這塈畯抰嚝 Northwind 資料庫。在“設置”頁上選擇希望的設置,至少要選上“允許範本查詢”和“允許 Post”。
在“虛擬名稱”頁中,從類型下拉式列示方塊中選擇“範本”,並輸入一個虛擬名稱(在這塈畯怢洏峞含emplate”)和物理路徑(它應該是虛擬目錄的一個子目錄,在這奡N是 "Template"子目錄),這是使用範本的需要。好,單擊“確定”。
現在我們測試一下是否每樣東西都設置正確了,我們將通過使用你拷貝到 Template 子目錄中去得 GetAllCustomers.xml來訪問 SQL Server。它的內容如下:
<root xmlns:sql="urn:schemas-microsoft-com:xml-sql">
<sql:query client-side-xml="0">
SELECT *
FROM Customers
FOR XML AUTO
</sql:query>
</root>
為了測試的目的,打開你的流覽器,並輸入這個URL: http://localhost/northwind/template/getallcustomers.xml,你就會在流覽器中看到XML形式的 Northwind Customers 表的內容了。
<root xmlns:sql='urns:schemas-micorsoft-com:xml-sql">
<Customers CustomerID="ALFKI" CompanyName="Alfreds Futterkiste" ContactName = "Maria Anders"
ContactTitle="Sales Represendative"
Address="Obere Str. 57" City="Berlin" PostalCode="12209"
Country="Germany" Phone="030-0074321"
Fax="999-999-9999" />
現在你就已經做好運行這篇文章的 SQLXML 示例的準備了。
******************************************************

_________________
#############################
快樂媽咪系列幸福宅配,喝十全雞湯~原來幸福那麼簡單!!

學會VFP使用者社區的搜尋,Code才會更有趣~
#############################
回頂端
檢視會員個人資料 發送私人訊息
從之前的文章開始顯示:   
發表新主題   回覆主題    VFP 愛用者社區 首頁 -> VFP 討論區 所有的時間均為 台北時間 (GMT + 8 小時)
1頁(共1頁)

 
前往:  
無法 在這個版面發表文章
無法 在這個版面回覆文章
無法 在這個版面編輯文章
無法 在這個版面刪除文章
無法 在這個版面進行投票
無法 在這個版面附加檔案
無法 在這個版面下載檔案


Powered by phpBB © 2001, 2005 phpBB Group
正體中文語系由 phpbb-tw 維護製作