VFP的數據策略:高級篇html
做者:Doug Hennig 翻譯:老瓷node
在「VFP中的數據策略:基礎篇」一文中,咱們研究了VFP應用程序中訪問非VFP數據(如SQL Server)的不一樣機制:遠程視圖、SQL Passthrough、ADO、XML和VFP 8中添加的CursorAdapter類。在本文中,咱們將更詳細地討論CursorAdapter,並討論可重用數據類的概念。此外,咱們將簡要介紹新的XMLAdapter基類,並瞭解它如何幫助與其餘源(如ADO.NET)交換數據。web
在我看來,CursorAdapter是VFP 8中最大的新特性之一。我以爲他們這麼酷的緣由是:sql
最後是一個例子。假設您有一個應用程序使用帶有CursorAdapter的ODBC來訪問SQL Server數據,出於某種緣由,您但願更改成使用ADO相反。您只需更改CursorAdapters的DataSourceType並更改到後端數據庫的鏈接,就完成了。應用程序中的其餘組件既不知道也不關心這一點;它們仍然看到同一個遊標,而無論用於訪問數據的機制如何。數據庫
讓咱們開始經過查看CursorAdapter的屬性、事件和方法(PEMs)來檢查它們。編程
這裏咱們不討論CursorAdapter類的全部屬性、事件和方法,只討論更重要些的屬性、事件和方法。有關完整列表,請參閱VFP文檔。
(PEMS:屬性、事件、方法統稱的縮寫——譯者注)後端
這個屬性很重要:它決定了類的行爲,以及將什麼類型的值放入其餘一些屬性中。有效的選項是「Native」,這表示您使用的是Native表,或者是選擇「ODBC」、「ADO」或「XML」,這表示您使用了適當的機制來訪問數據。您可能不會使用「Native」,由於您可能會使用Cursor對象而不是CursorAdapter,但此設置將使之後升遷應用程序更容易。數組
這是訪問數據的方法。當DataSourceType設置爲「Native」或「XML」時,VFP忽略此屬性。對於ODBC,將DataSource設置爲有效的ODBC鏈接句柄(這意味着您必須本身管理鏈接)。對於ADO,數據源必須是一個ADO記錄集,該記錄集的ActiveConnection對象設置爲打開的ADO鏈接對象(一樣,您必須本身管理)。服務器
若是此屬性設置爲.T(默認值爲.F),則能夠不使用DataSourceType和DataSource屬性,由於CursorAdapter將使用數據環境(DataEnvironment)的屬性(VFP 8也將DataSourceType和DataSource添加到DataEnvironment類)。將此設置爲.T.的一個示例是,但願數據環境中的全部CursorAdapter使用相同的ODBC鏈接。併發
對於除了XML之外的全部內容,這是用於檢索數據的SQL SELECT命令。對於XML,這能夠是能夠轉換爲遊標的有效XML字符串(使用內部XMLTOCURSOR()調用)或返回有效XML字符串的表達式(如UDF)。
此屬性保存遊標的結構,其格式與您在CREATE Cursor命令中使用的格式相同(此類命令中括號之間的全部內容)。這裏有一個例子:CUST_ID C(6),COMPANY C(30),CONTACT C(30),CITY C(25)。儘管能夠將此項留空,並告訴CursorAdapter在建立遊標時肯定結構,但若是將CursorSchema填充進來,效果會更好。首先,若是CursorSchema爲空或不正確,則在打開窗體的數據環境時可能會出錯,或者沒法將字段從CursorAdapter拖放到窗體以建立控件。幸運的是,VFP附帶的CursorAdapter構建器能夠自動爲您填充這個內容。
這些屬性(默認爲.T)決定是否能夠執行刪除、插入和更新,以及是否將更改發送到數據源。
若是但願VFP使用遊標中所作的更改自動更新數據源,則須要這些屬性,這些屬性的用途與視圖的同名CursorSetProp()屬性相同。KeyFieldList是一個逗號分隔的字段列表(不帶別名),這些字段構成遊標的主鍵。表是一個逗號分隔的表列表。UpdateableFieldList是一個逗號分隔的字段列表(沒有別名),能夠更新。UpdateNameList是一個逗號分隔的列表,它將遊標中的字段名與表中的字段名相匹配。UpdateNameList的格式以下:CursorFieldName1 Table.FieldName1,CursorFieldName2 Table.FieldName2……請注意,即便UpdateableFieldList不包含表的主鍵的名稱(由於您不但願更新該字段),它也必須仍然存在於UpdateNameList中,不然更新將不起做用。
若是要特別控制VFP如何刪除、插入或更新數據源中的記錄,能夠爲這些屬性集指定適當的值(將上面的*替換爲Delete、Insert和Update)。
此方法建立遊標並用數據源中的數據填充它(儘管能夠經過.T.使NoData參數建立空遊標)。對於第一個使用CursorSchema或.F中定義的模式的參數,傳遞.T。以從數據源建立適當的結構(在我看來,這種行爲是相反的)。必須設置多鎖,不然此方法將失敗。若是CursorFill因爲任何緣由失敗,它將返回.F,而不是引起錯誤;使用AERROR()來肯定出了什麼問題(儘管準備好進行一些深挖,由於您常常收到的錯誤消息不夠具體,沒法確切地告訴您問題是什麼)。
此方法相似於ReQuery()函數:它刷新遊標的內容。
幾乎每一個方法和事件都有先後「鉤子」事件,容許您自定義CursorAdapter的行爲。例如,在AfterCursorFill中,能夠爲遊標建立索引,使其始終可用。對於Before事件,能夠返回.F.以防止觸發它的操做發生(這與數據庫事件相似)。
下面是一個示例(CursorAdapterExample.prg),它從SQL Server附帶的Northwind數據庫的Customers表中獲取巴西客戶的某些字段。遊標是可更新的,所以若是您在遊標中進行了更改,請將其關閉,而後再次運行程序,您將看到您的更改已保存到後端。
local loCursor as CursorAdapter, ; laErrors[1] loCursor = createobject('CursorAdapter') with loCursor .Alias = 'Customers' .DataSourceType = 'ODBC' .DataSource = sqlstringconnect('driver=SQL Server;' + ; 'server=(local);database=Northwind;uid=sa;pwd=;trusted_connection=no') .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、Form類及其設計器進行了一些更改。
首先,如前所述,DataEnvironment類如今有DataSource和DataSourceType屬性。它自己不使用這些屬性,但已將UseDataSource設置爲.T.的任何CursorAdapter成員都使用這些屬性。其次,如今可使用類設計器(woo-hoo!)可視化地建立DataEnvironment子類。
至於表單,如今能夠經過設置新的DEClass和DEClassLibrary屬性來指定要使用的DataEnvironment子類。若是您這樣作,您對現有數據環境所作的任何事情(遊標、代碼等)都將丟失,但至少您會首先收到警告。表單的一個很酷的新特性是BindControls屬性;在屬性窗口中將其設置爲.F. 意味着VFP不會在初始化時嘗試對控件進行數據綁定,只有在將BindControls設置爲.T.時纔會這樣作。這有什麼好處?好吧,您詛咒參數傳遞給Init多少次了,Init在全部控件初始化並綁定到它們的ControlSource以後觸發?若是要將參數傳遞給告訴它要打開哪一個表的窗體或其餘影響ControlSources的內容,該怎麼辦?這個新屬性使這個問題很快解決。
CursorGetProp('SourceType')返回一個新的值範圍:若是遊標是用CursorFill建立的,則該值爲100加上舊值(例如,遠程數據爲102)。若是遊標是用CursorAttach建立的(容許您將現有遊標附加到CursorAdapter對象),則該值爲200加上舊值。若是數據源是ADO記錄集,則值爲104(CursorFill)或204(CursorAttach)。
VFP包括DataEnvironment和CursorAdapter構造器(或稱爲生成器——譯者注),使得使用這些類更加容易。
以正常方式啓動DataEnvironment Builder:在類設計器中右鍵單擊窗體的DataEnvironment或DataEnvironment子類,而後選擇Builder。數據環境生成器的「數據源」頁是設置數據源信息的位置。選擇所需的數據源類型和數據源的來源。若是選擇「使用現有鏈接句柄」(ODBC)或「使用現有ADO記錄集」(ADO),請指定包含數據源的表達式(例如「goConnectionMgr.nHandle」)。您還能夠選擇使用系統上的任一個DSN或鏈接字符串。只有在爲ADO選擇「使用鏈接字符串」時纔會啓用「生成」按鈕,該按鈕將顯示「數據連接屬性」對話框,您可使用該對話框直觀地生成鏈接字符串。若是選擇「使用DSN」或「使用鏈接字符串」,生成器將在數據環境的BeforeOpenTables方法中生成代碼以建立所需的鏈接。若是選擇「Native」,則能夠選擇VFP數據庫容器做爲數據源;在這種狀況下,生成的代碼將確保數據庫是打開的(也可使用自由表做爲數據源)。
「Cursors」頁面容許您維護DataEnvironment的CursorAdapter成員(遊標對象不會在生成器中顯示,也不能添加它們)。Add按鈕容許您向DataEnvironment添加CursorAdapter子類,而New則建立一個新的基類CursorAdapter。Remove刪除Select CursorAdapter,Builder爲所選CursorAdapter調用CursorAdapter Builder。您能夠更改CursorAdapter對象的名稱,但對於任何其餘屬性,都須要CursorAdapter生成器。
從快捷菜單中選擇Builder也能夠調用CursorAdapter生成器。「Properties」頁顯示對象的類和名稱(只有在從DataEnvironment中調出生成器時才能更更名稱,由於它對CursorAdapter子類是隻讀的)、它將建立的遊標的別名、是否應該使用DataEnvironment的數據源以及鏈接信息(若是沒有)。與DataEnvironment生成器同樣,若是選擇「使用DSN」或「使用鏈接字符串」,CursorAdapter生成器將生成代碼以建立所需的鏈接(在本例中是CursorFill方法)。
「數據訪問」頁容許您指定SelectCmd、CursorSchema和其餘屬性。若是您指定了鏈接信息,能夠單擊SelectCmd的Build按鈕來顯示Select Command Builder,這樣就能夠輕鬆地建立SelectCmd。
Select命令生成器簡化了構建一個簡單的Select語句的工做。從「表格」下拉列表中選擇所需的表格,而後將相應的字段移到選定的一側。對於本機數據源,能夠向「表」組合框中添加表(例如,若是但願使用空閒表)。選擇OK時,SelectCmd將填充適當的SQL SELECT語句。
單擊遊標模式的「生成」按鈕,自動爲您填寫此屬性。爲了使其工做,生成器實際上建立了一個新的CursorAdapter對象,適當地設置了屬性,並調用CursorFill來建立遊標。若是您沒有到數據源的實時鏈接,或者CursorFill因爲某種緣由(例如無效的SelectCmd)失敗,那麼這顯然行不通。
使用「自動更新」頁設置VFP自動爲數據源生成更新語句所需的屬性。Tables屬性是從SelectCmd中指定的表自動填充的,fields網格是從CursorSchema中的字段填充的。與視圖設計器同樣,能夠經過檢查網格中的相應列來選擇哪些是關鍵字段,哪些字段是可更新的。還能夠設置其餘屬性,例如在將遊標發送到數據源以前轉換遊標某些字段中的數據的函數。
更新、插入和刪除頁面的外觀幾乎相同。它們容許您爲更新、刪除和插入屬性集指定值。對於VFP不能自動生成update語句的XML,這一點尤其重要。
儘管很明顯CursorAdapter的目的是爲了標準化和簡化對非VFP數據的訪問,可是您能夠經過將DataSourceType設置爲「Native」來使用它來替代Cursor。你爲什麼這樣作?主要是傾向於未來應用程序升級;經過簡單地將DataSourceType更改成其餘選項之一(並可能更改其餘一些屬性,如設置鏈接信息),您能夠輕鬆地切換到其餘DBMS,如SQL Server。
當DataSourceType設置爲「Native」時,VFP將忽略DataSource。SelectCmd必須是一個SQL SELECT語句,而不是USE命令或表達式,這意味着您老是使用至關於本地視圖的語句,而不是直接使用表。您須確保VFP可找到SELECT語句中引用的任何表,所以若是這些表不在當前目錄中,則須要設置路徑或打開表所屬的數據庫。與往常同樣,若是但願遊標可更新,請確保設置更新屬性(KeyFieldList、Tables、UpdateableFieldList和UpdateNameList)。
如下示例(NativeExample.prg)從TestData VFP示例數據庫中的Customer表建立一個可更新的遊標:
local loCursor as CursorAdapter, ; laErrors[1] open database (_samples + 'data\testdata') loCursor = createobject('CursorAdapter') 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其實是DataSourceType的四個設置中最直接的一個。將DataSource設置爲打開的ODBC鏈接句柄,設置經常使用屬性,而後調用CursorFill來檢索數據。若是您填寫KeyFieldList、Tables、UpdateableFieldList和UpdateNameList,VFP將自動生成適當的UPDATE、INSERT和DELETE語句,以便用任何更改更新後端。若是要改用存儲過程,請適當設置*Cmd、*CmdDataSource和*CmdDataSourceType屬性。
下面是一個示例,取自ODBCExample.prg,它調用Northwind數據庫中的CustOrderHist存儲過程,以獲取特定客戶按產品銷售的總單位:
local loCursor as CursorAdapter, ; laErrors[1] loCursor = createobject('CursorAdapter') with loCursor .Alias = 'CustomerHistory' .DataSourceType = 'ODBC' .DataSource = sqlstringconnect('driver=SQL Server;server=(local);' + ; 'database=Northwind;uid=sa;pwd=;trusted_connection=no') .SelectCmd = "exec CustOrderHist 'ALFKI'" if .CursorFill() browse else aerror(laErrors) messagebox(laErrors[2]) endif .CursorFill() endwith
使用ADO做爲CursorAdapter的數據訪問機制比使用ODBC有更多的問題:
下面的示例代碼取自ADOExample.prg,它展現瞭如何在ADO命令對象的幫助下使用參數化查詢檢索數據。這個例子還展現了VFP 8中新的結構化錯誤處理特性的使用;對ADO鏈接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=;trusted_connection=no' 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源能夠來自不一樣的地方。例如,能夠調用一個UDF,該UDF使用CURSORTOXML()將VFP遊標轉換爲XML,並返回結果:
use CUSTOMERS cursortoxml('customers', 'lcXML', 1, 8, 0, '1') return lcXML
UDF能夠調用返回結果集爲XML的Web服務。下面是一個從我在本身的系統上建立和註冊的Web服務中爲我生成的自動感應示例(細節並不重要;它只是顯示了一個Web服務的示例)。
local loWS as dataserver 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
它可使用SQLXML 3.0執行存儲在Web服務器模板文件中的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)來執行更新。
下面是一個示例(XMLExample.prg),它使用帶有XML數據源的CursorAdapter。注意,SelectCmd和UpdateCmd都調用UDF。在SelectCmd的狀況下,SQL Server 2000 XML模板的名稱和要檢索的客戶ID被傳遞給一個名爲GetNWXML的UDF,稍後咱們將討論這個UDF。對於UpdateCmd,VFP將UpdateGram屬性傳遞給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 = 'GetNWXML([customersbyid.xml?customerid=ALFKI])' .Tables = 'CUSTOMERS' .UpdatableFieldList = 'CUSTOMERID, COMPANYNAME, CONTACTNAME, ' + ; 'CONTACTTITLE, ADDRESS, CITY, REGION, POSTALCODE, COUNTRY, PHONE, FAX' .UpdateCmdDataSourceType = 'XML' .UpdateCmd = 'SendNWXML(This.UpdateGram)' .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
此代碼引用的XML模板CustomersByID.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數據庫的虛擬目錄中(有關配置IIS以使用SQL Server的詳細信息,請參閱附錄)。
這是GetNWXML的代碼。它使用MSXML2.XMLHTTP對象訪問Web服務器上的SQL Server 2000 XML模板並返回結果。模板的名稱(以及可選的任何查詢參數)做爲參數傳遞給此代碼。
lparameters tcURL local loXML as MSXML2.XMLHTTP loXML = createobject('MSXML2.XMLHTTP') loXML.open('POST', 'http://localhost/northwind/template/' + tcURL, .F.) loXML.setRequestHeader('Content-type', 'text/xml') loXML.send() return loXML.responseText
SendNWXML看起來很類似,只是它但願傳遞一個diffgram,將diffgram加載到MSXML2.DOMDocument對象中,並將該對象傳遞給Web服務器,而後Web服務器將經過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。您應該在瀏覽窗口中看到一條記錄(ALFKI客戶)。更改某個字段中的值,而後關閉窗口並再次運行PRG。您應該看到您的更改已寫入後端。
與VFP中一般的狀況同樣,我建立了CursorAdapter和DataEnvironment的子類,我將使用這些子類而不是基類。
SFCursorAdapter(在SFDataClasses.vcx中)是CursorAdapter的一個子類,它添加了一些附加功能:
讓咱們來看看這個類。
Init方法建立兩個集合(使用新的集合基類,它維護事物的集合),一個用於SelectCmd屬性可能須要的參數,另外一個用於在遊標打開後應自動建立的標記。它還設置了MULTILOCKS on,由於這是CursorAdapter遊標所必需的。
with This * 建立參數和標記集合 .oParameters = createobject('Collection') .oTags = createobject('Collection') * 確保 MULTILOCKS 設置爲 on. set multilocks on endwith
AddParameter方法向parameters集合添加一個參數。向此方法傳遞參數的名稱(該名稱應與SelectCmd屬性中顯示的名稱匹配)和可選的參數值(若是如今不傳遞,能夠稍後使用GetParameter方法進行設置)。這段代碼展現了VFP 8中的兩個新特性:新的Empty類(沒有PEMs),使其成爲輕量級對象的理想選擇;ADDPROPERTY()函數(其做用相似於那些沒有該方法的對象的ADDPROPERTY方法)。
lparameters tcName, ; tuValue local loParameter loParameter = createobject('Empty') addproperty(loParameter, 'Name', tcName) addproperty(loParameter, 'Value', tuValue) This.oParameters.Add(loParameter, tcName)
使用GetParameter方法返回一個特定的參數對象;當您想設置要用於參數的值時,一般會使用這個方法。
lparameters tcName local loParameter loParameter = This.oParameters.Item(tcName) return loParameter
SetConnection方法用於將DataSource屬性設置爲所需的鏈接。若是DataSourceType是「ODBC」,請傳遞鏈接句柄。若是是「ADO」,則數據源須要是一個ADO記錄集,其ActiveConnection屬性設置爲打開的ADO鏈接對象,所以經過Connection對象,SetConnection將建立記錄集並將其ActiveConnection設置爲傳遞對象。
lparameters tuConnection with This do case case .DataSourceType = 'ODBC' .DataSource = tuConnection case .DataSourceType = 'ADO' .DataSource = createobject('ADODB.RecordSet') .DataSource.ActiveConnection = tuConnection endcase endwith
要建立遊標,請調用GetData方法而不是CursorFill,由於它會自動處理參數和錯誤。若是要建立遊標但不填充數據,請將.T.傳遞給GetData。此方法所作的第一件事是建立私有範圍的變量,這些變量的名稱和值與參數集合中定義的參數相同(從這裏調用的GetParameterValue方法返回參數對象的值或以「=」開頭的值的求值)。接下來,若是咱們使用ADO而且有任何參數,代碼將建立一個ADO Command對象並將其ActiveConnection設置爲Connection對象,而後將Command對象傳遞給CursorFill方法;CursorAdapter要求在參數化ADO查詢中使用該方法。若是咱們沒有使用ADO或者沒有任何參數,代碼只調用cursor fill來填充遊標。注意.T.被傳遞給CursorFill,告訴它在CursorSchema被填充時使用CursorSchema(這是我但願基類具備的行爲)。若是建立了遊標,則代碼調用CreateTags方法爲遊標建立所需的索引;若是沒有,則調用HandleError方法來處理髮生的任何錯誤。
lparameters tlNoData local loParameter, ; lcName, ; luValue, ; llUseSchema, ; loCommand, ; llReturn with This *若是咱們要填充遊標(而不是建立空遊標),則建立變量來保存任何參數 *必須在這裏而不是在方法中這樣作,由於咱們但願它們的做用域是私有的 if not tlNoData for each loParameter in .oParameters lcName = loParameter.Name luValue = .GetParameterValue(loParameter) store luValue to (lcName) next loParameter endif not tlNoData *若使用ADO且有參數,則需一個Command對象來處理這個問題 llUseSchema = not empty(.CursorSchema) if '?' $ .SelectCmd and (.DataSourceType = 'ADO' or (.UseDEDataSource and ; .Parent.DataSourceType = 'ADO')) loCommand = createobject('ADODB.Command') loCommand.ActiveConnection = iif(.UseDEDataSource, ; .Parent.DataSource.ActiveConnection, .DataSource.ActiveConnection) llReturn = .CursorFill(llUseSchema, tlNoData, .nOptions, loCommand) else *嘗試填充遊標 llReturn = .CursorFill(llUseSchema, tlNoData, .nOptions) endif '?' $ .SelectCmd ... *若是咱們建立了遊標,請建立爲其定義的任何標記。 *若是沒有,請處理錯誤。 if llReturn .CreateTags() else .HandleError() endif llReturn endwith return llReturn
Update方法很簡單:它只調用TABLEUPDATE()嘗試更新原始數據源,若是失敗則調用HandleError。
local llReturn llReturn = tableupdate(1, .F., This.Alias) if not llReturn This.HandleError() endif not llReturn return llReturn
有幾種方法咱們在這裏不看,你能夠本身檢查一下。AddTag將遊標建立後要建立的索引的信息添加到tags集合,而CreateTags(從GetData調用)在INDEX ON語句中使用該集合中的信息。HandleError使用AERROR()來肯定出錯的地方,並將錯誤數組的第二個元素放入cErrorMessage屬性中。
讓咱們看幾個使用這個類的例子。第一個(取自TestCursorAdapter.prg)從Northwind數據庫的Customers表中獲取全部記錄。這段代碼與用於基類CursorAdapter的代碼沒有太大的不一樣(因爲沒有填寫CursorSchema,所以必須將.F.做爲第一個參數傳遞給CursorFill)。
loCursor = newobject('SFCursorAdapter', 'SFDataClasses') with loCursor *鏈接到SQL Server Northwind數據庫並獲取客戶記錄 .DataSourceType = 'ODBC' .DataSource = sqlstringconnect('driver=SQL Server;server=(local);' + ; 'database=Northwind;uid=sa;pwd=;trusted_connection=no') .Alias = 'Customers' .SelectCmd = 'select * from customers' if .GetData() browse else messagebox('Could not get the data. The error message was:' + ; chr(13) + chr(13) + .cErrorMessage) endif .GetData() endwith
下一個示例(也取自TestCursorAdapter.prg)使用SFConnectionMgr的ODBC版原本管理鏈接,咱們在「VFP中的數據策略:基礎篇」一文中查看了該版本。它還爲SelectCmd使用參數化語句,顯示AddParameter方法如何容許您處理參數,並演示如何使用AddTag方法自動爲遊標建立標記。
loConnMgr = newobject('SFConnectionMgrODBC', 'SFRemote') with loConnMgr .cDriver = 'SQL Server' .cServer = '(local)' .cDatabase = 'Northwind' .cUserName = 'sa' .cPassword = '' endwith if loConnMgr.Connect() loCursor = newobject('SFCursorAdapter', 'SFDataClasses') with loCursor .DataSourceType = 'ODBC' .SetConnection(loConnMgr.GetConnection()) .Alias = 'Customers' .SelectCmd = 'select * from customers where country = ?pcountry' .AddParameter('pcountry', 'Brazil') .AddTag('CustomerID', 'CustomerID') .AddTag('Company', 'upper(CompanyName)') .AddTag('Contact', 'upper(ContactName)') if .GetData() messagebox('Brazilian customers in CustomerID order') set order to CustomerID go top browse messagebox('Brazilian customers in Contact order') set order to Contact go top browse messagebox('Canadian customers') loParameter = .GetParameter('pcountry') loParameter.Value = 'Canada' .Requery() browse else messagebox('Could not get the data. The error message was:' + ; chr(13) + chr(13) + .cErrorMessage) endif .GetData() endwith else messagebox(loConnMgr.cErrorMessage) endif loConnMgr.Connect()
SFDataEnvironment(也在SFDataClasses.vcx中)比SFCursorAdapter簡單得多,但添加了一些有用的功能:
GetData很是簡單:它只調用具備該方法的任何成員對象的GetData方法。
lparameters tlNoData local loCursor, ; llReturn for each loCursor in This.Objects if pemstatus(loCursor, 'GetData', 5) llReturn = loCursor.GetData(tlNoData) if not llReturn This.cErrorMessage = loCursor.cErrorMessage exit endif not llReturn endif pemstatus(loCursor, 'GetData', 5) next loCursor return llReturn
SetConnection稍微複雜一點:它調用任何具備該方法且UseDEDataSource設置爲.F.的成員對象的SetConnection方法,而後使用相似於SFCursorAdapter中的代碼設置本身的數據源(若是任何CursorAdapter的UseDEDataSource設置爲.T.)。
lparameters tuConnection local llSetOurs, ; loCursor, ; llReturn with This *調用任何不使用數據源的CursorAdapter的SetConnection方法 llSetOurs = .F. for each loCursor in .Objects do case case upper(loCursor.BaseClass) <> 'CURSORADAPTER' case loCursor.UseDEDataSource llSetOurs = .T. case pemstatus(loCursor, 'SetConnection', 5) loCursor.SetConnection(tuConnection) endcase next loCursor *若是發現使用數據源的CursorAdapter,須要設置數據源 if llSetOurs do case case .DataSourceType = 'ODBC' .DataSource = tuConnection case .DataSourceType = 'ADO' .DataSource = createobject('ADODB.RecordSet') .DataSource.ActiveConnection = tuConnection endcase endif llSetOurs endwith
Requery和Update幾乎與GetData相同,因此咱們沒必要費心去查看它們。
TestDE.prg顯示瞭如何使用SFDataEnvironment做爲兩個SFCursorAdapter類的容器。因爲此示例使用ADO,所以每一個SFCursorAdapter都須要本身的數據源,故UseDEDataSource設置爲.F。請注意,對DataEnvironment SetConnection方法的單個調用負責爲每一個CursorAdapter設置數據源屬性。
loConnMgr = newobject('SFConnectionMgrADO', 'SFRemote') with loConnMgr .cDriver = 'SQLOLEDB.1' .cServer = '(local)' .cDatabase = 'Northwind' .cUserName = 'sa' .cPassword = '' endwith if loConnMgr.Connect() loDE = newobject('SFDataEnvironment', 'SFDataClasses') with loDE .NewObject('CustomersCursor', 'SFCursorAdapter', 'SFDataClasses') with .CustomersCursor .Alias = 'Customers' .SelectCmd = 'select * from customers' .DataSourceType = 'ADO' endwith .NewObject('OrdersCursor', 'SFCursorAdapter', 'SFDataClasses') with .OrdersCursor .Alias = 'Orders' .SelectCmd = 'select * from orders' .DataSourceType = 'ADO' endwith .SetConnection(loConnMgr.GetConnection()) if .GetData() select Customers browse nowait select Orders browse else messagebox('Could not get the data. The error message was:' + ; chr(13) + chr(13) + .cErrorMessage) endif .GetData() endwith else messagebox(loConnMgr.cErrorMessage) endif loConnMgr.Connect()
如今咱們有了CursorAdapter和DataEnvironment子類,讓咱們討論一下可重用的數據類。
VFP開發人員要求微軟在VFP中添加的一件事是可重用的數據環境。例如,您可能有一個表單和一個報表具備徹底相同的數據設置,可是您必須手動爲每一個表單和報表填充數據環境,由於數據環境是不可重用的。一些開發人員(以及幾乎全部的框架供應商)經過在代碼中建立數據環境(它們不能可視化地被子類化)並在表單上使用「loader」對象來實例化數據環境子類,使得建立可重用的數據環境變得更加容易。然而,這是一種混亂,並無幫助報告。
如今,在VFP 8中,咱們可以建立兩個可重用的數據類,它們能夠提供從任何數據源到任何須要它們的數據源的遊標,以及可重用的數據環境,後者能夠託管數據類。在撰寫本文時,您不能在報表中使用CursorAdapter或DataEnvironment子類,但能夠經過編程添加CursorAdapter子類(例如在DataEnvironment的Init方法中)來利用那裏的可重用性。
咱們來爲Northwind客戶和訂單表建立數據類。首先,建立SFCursorAdapter的一個子類CustomersCursor並設置屬性,以下所示。
屬性 | 值 |
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) |
KeyFieldList | CUSTOMERID |
SelectCmd | select * from customers |
Tables | CUSTOMERS |
UpdatableFieldList | CUSTOMERID, COMPANYNAME, CONTACTNAME, CONTACTTITLE, ADDRESS, CITY, REGION, POSTALCODE, COUNTRY, PHONE, FAX |
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 |
備註:您可使用CursorAdapter生成器完成大部分工做,特別是設置CursorSchema和更新屬性。訣竅是打開「use connection settings in builder only」(僅在生成器中使用鏈接設置)選項,填寫鏈接信息以創建實時鏈接,而後填寫SelectCmd並使用生成器爲您構建其他屬性。
如今,只要您須要Northwind Customers表中的記錄,就只需使用CustomersCursor類。固然,咱們尚未定義任何鏈接信息,但這其實是件好事,由於這個類沒必要擔憂如何獲取數據(ODBC、ADO或XML),甚至沒必要擔憂要使用什麼數據庫引擎(用於SQL Server、Access和新版VFP8的Northwind數據庫)。
可是請注意,這個遊標涉及Customers表中的全部記錄。有時候,你只想要一個特定的客戶。因此,讓咱們建立一個CustomersCursor的子類CustomerByIDCursor。將SelectCmd更改成「select * from customers where customerid = ?pcustomerid」並將如下代碼放入Init:
lparameters tcCustomerID dodefault() This.AddParameter('pCustomerID', tcCustomerID)
這將建立一個名爲pCustomerID的參數(與SelectCmd中指定的名稱相同),並將其設置爲傳遞的任意值。若是未傳遞任意值,請使用GetParameter返回此參數的對象,並在調用GetData以前設置其Value屬性。
建立一個相似於CustomersCursor的orderscorsor類,只是它從Orders表中檢索全部記錄。而後建立一個OrdersForCustomerCursor子類,該子類只檢索特定客戶的訂單。將SelectCmd設置爲「select * from orders where customerid = ?pcustomerid」,並將與CustomerByIDCursor相同的代碼放入Init(由於它是相同的參數)。
要測試其效果,請運行TestCustomersCursor.prg。
如今咱們有了一些可重用的數據類,來用一下它們。首先,讓咱們建立一個名爲CustomersAndOrdersDataEnvironment的SFDataEnvironment子類,它包含CustomerByIDCursor和OrdersForCustomerCursor類。將AutoOpenTables設置爲.F(由於咱們須要在打開表以前設置鏈接信息),並將CursorAdapter和UseDEDataSource設置爲.T。如今能夠以某種形式使用此數據環境來顯示有關特定客戶的信息,包括其訂單。
讓咱們建立這樣一個表單。建立一個名爲CustomerOrders.scx的表單(它包含在本文檔附帶的示例文件中),將DEClass和DEClassLibrary設置爲CustomersAndOrdersDataEnvironment,以便咱們使用可重用的數據環境。將如下代碼放入Load方法中:
#define ccDATASOURCETYPE 'ADO' with This.CustomersAndOrdersDataEnvironment *設置數據環境數據源 .DataSourceType = ccDATASOURCETYPE *若是咱們使用ODBC或ADO,請建立一個鏈接管理器 *並打開鏈接到Northwind數據庫的鏈接 if .DataSourceType $ 'ADO,ODBC' This.AddProperty('oConnMgr') This.oConnMgr = newobject('SFConnectionMgr' + ccDATASOURCETYPE, ; 'SFRemote') with This.oConnMgr .cDriver = iif(ccDATASOURCETYPE = 'ADO', 'SQLOLEDB.1', ; 'SQL Server') .cServer = '(local)' .cDatabase = 'Northwind' .cUserName = 'sa' .cPassword = '' endwith if not This.oConnMgr.Connect() messagebox(oConnMgr.cErrorMessage) return .F. endif not This.oConnMgr.Connect() *若是咱們使用ADO,每一個遊標都必須有本身的數據源 if .DataSourceType = 'ADO' .CustomerByIDCursor.UseDEDataSource = .F. .CustomerByIDCursor.DataSourceType = 'ADO' .OrdersForCustomerCursor.UseDEDataSource = .F. .OrdersForCustomerCursor.DataSourceType = 'ADO' endif .DataSourceType = 'ADO' *將數據源設置爲鏈接 .SetConnection(This.oConnMgr.GetConnection()) *若是使用的是XML,請更改SelectCmd以調用GetNWXML函數 else .CustomerByIDCursor.SelectCmd = 'GetNWXML([customersbyid.xml?' + ; 'customerid=] + pCustomerID)' .CustomerByIDCursor.UpdateCmdDataSourceType = 'XML' .CustomerByIDCursor.UpdateCmd = 'SendNWXML(This.UpdateGram)' .OrdersForCustomerCursor.SelectCmd = 'GetNWXML([ordersforcustomer.' + ; 'xml?customerid=] + pCustomerID)' .OrdersForCustomerCursor.UpdateCmdDataSourceType = 'XML' .OrdersForCustomerCursor.UpdateCmd = 'SendNWXML(This.UpdateGram)' endif .DataSourceType $ 'ADO,ODBC' *指定將從CustomerID文本框中填充遊標參數的值 loParameter = .CustomerByIDCursor.GetParameter('pCustomerID') loParameter.Value = '=Thisform.txtCustomerID.Value' loParameter = .OrdersForCustomerCursor.GetParameter('pCustomerID') loParameter.Value = '=Thisform.txtCustomerID.Value' *建立空遊標並在失敗時顯示錯誤消息 if not .GetData(.T.) messagebox(.cErrorMessage) return .F. endif not .GetData(.T.) endwith
這看起來像不少代碼,但其中大部分是爲了演示目的,以容許切換到不一樣的數據訪問機制。
此代碼建立一個鏈接管理器來處理鏈接(ADO、ODBC或XML),具體取決於ccDATASOURCETYPE常量,您能夠更改該常量以嘗試每一個機制。對於ADO,因爲每一個CursorAdapter都必須有本身的數據源,所以爲每一個CursorAdapter設置UseDEDataSource和DataSourceType屬性。而後,代碼調用SetConnection方法來設置鏈接信息。對於XML,SelectCmd、UpdateCmdDataSourceType和UpdateCmd屬性必須如前所述進行更改。接下來,代碼使用兩個CursorAdapter對象的GetParameter方法將pCustomerID參數的值設置爲表單中文本框的內容。注意在值中使用「=」;這意味着每次須要時都會對Value屬性求值,所以咱們基本上有一個動態參數(當用戶在文本框中鍵入時,保存將參數不斷更改成當前值的須要)。最後,調用GetData方法來建立空遊標,以便控件的數據綁定能夠工做。
在表單上放置一個文本框並將其命名爲txtCustomer,將如下代碼放入其Valid方法中:
with Thisform .CustomersAndOrdersDataEnvironment.Requery() .Refresh() endwith
這將致使在輸入客戶ID時從新查詢遊標和刷新控件。
在表單上放置一個標籤,放在文本框旁邊,並將其標題設置爲「客戶ID」。
將CompanyName、ContactName、Address、City、Region、PostalCode和Country字段從DataEnvironment中的Customers遊標拖動到表單中,以建立這些字段的控件。而後在Orders遊標中選擇OrderID、EmployeeID、OrderDate、RequiredDate、ShippedDate、ShipVia和Freight字段,並將它們拖到表單中以建立網格(Grid--譯者注)。
就這樣子。運行表單並輸入「ALFKI」做爲客戶ID。當您在文本框中選擇選項卡時,您應該會看到客戶地址信息和訂單。嘗試更改有關客戶或訂單的內容,而後關閉表單,再次運行它,而後再次輸入「ALFKI」。您應該看到,您所作的更改已寫入後端數據庫,而無需您付出任何努力。
很酷吧?這比基於本地表或視圖建立表單要簡單得多。更好的方法是,嘗試將ccDATASOURCETYPE常量更改成「ADO」或「XML」,並注意表單的外觀和工做方式徹底相同。這就是CursorAdapters的要點!
咱們試一個Report。此處討論的示例取自此文檔附帶的CustomerOrders.frx。這裏最大的問題是,與表單不一樣,咱們不能告訴報表使用DataEnvironment子類,也不能在DataEnvironment中刪除CursorAdapter子類。所以,咱們必須在報表中放入一些代碼,以便將CursorAdapter子類添加到數據環境中。儘管將此代碼放入報表數據環境的BeforeOpenTables事件中彷佛是合乎邏輯的,但實際上這不會起做用,由於我不明白爲何,在預覽報表時,BeforeOpenTables會在每一個頁面上激發。因此,咱們將把代碼放入Init方法中。
#define ccDATASOURCETYPE 'ODBC' with This set safety off *設置數據環境數據源 .DataSourceType = ccDATASOURCETYPE *爲客戶和訂單建立CursorAdapter對象 .NewObject('CustomersCursor', 'CustomersCursor', 'NorthwindDataClasses') .CustomersCursor.AddTag('CustomerID', 'CustomerID') .NewObject('OrdersCursor', 'OrdersCursor', 'NorthwindDataClasses') .OrdersCursor.AddTag('CustomerID', 'CustomerID') *若使用ODBC或ADO,請建立一個鏈接管理器 *並打開鏈接到Northwind數據庫的鏈接 if .DataSourceType $ 'ADO,ODBC' .AddProperty('oConnMgr') .oConnMgr = newobject('SFConnectionMgr' + ccDATASOURCETYPE, ; 'SFRemote') with .oConnMgr .cDriver = iif(ccDATASOURCETYPE = 'ADO', 'SQLOLEDB.1', ; 'SQL Server') .cServer = '(local)' .cDatabase = 'Northwind' .cUserName = 'sa' .cPassword = '' endwith if not .oConnMgr.Connect() messagebox(.oConnMgr.cErrorMessage) return .F. endif not .oConnMgr.Connect() *若是使用ADO,每一個遊標都必須有本身的數據源 if .DataSourceType = 'ADO' .CustomersCursor.UseDEDataSource = .F. .CustomersCursor.DataSourceType = 'ADO' .CustomersCursor.SetConnection(.oConnMgr.GetConnection()) .OrdersCursor.UseDEDataSource = .F. .OrdersCursor.DataSourceType = 'ADO' .OrdersCursor.SetConnection(.oConnMgr.GetConnection()) else .CustomersCursor.UseDEDataSource = .T. .OrdersCursor.UseDEDataSource = .T. .DataSource = .oConnMgr.GetConnection() endif .DataSourceType = 'ADO' .CustomersCursor.SetConnection(.oConnMgr.GetConnection()) .OrdersCursor.SetConnection(.oConnMgr.GetConnection()) *若使用XML,請更改SelectCmd以調用GetNWXML函數 else .CustomersCursor.SelectCmd = 'GetNWXML([getallcustomers.xml])' .CustomersCursor.DataSourceType = 'XML' .OrdersCursor.SelectCmd = 'GetNWXML([getallorders.xml])' .OrdersCursor.DataSourceType = 'XML' endif .DataSourceType $ 'ADO,ODBC' *獲取數據並在失敗時顯示錯誤消息 if not .CustomersCursor.GetData() messagebox(.CustomersCursor.cErrorMessage) return .F. endif not .CustomersCursor.GetData() if not .OrdersCursor.GetData() messagebox(.OrdersCursor.cErrorMessage) return .F. endif not .OrdersCursor.GetData() *設置從客戶到訂單的關係 set relation to CustomerID into Customers endwith
此代碼看起來與窗體的代碼相似。一樣,大多數代碼是處理不一樣的數據訪問機制。可是,還有一些額外的代碼,由於咱們不能使用DataEnvironment子類,必須本身編寫行爲代碼。
如今,咱們如何方便地把字段放在Report上?因爲CursorAdapter在設計時不存在於數據環境中,所以咱們不能將字段從它們拖到Report中。這裏有一個提示:建立一個PRG來建立遊標並將其留在做用域中(經過掛起或使CursorAdapter對象公開),而後使用Quick Report函數將具備適當大小的字段放在Report上。
在CUSTOMERS.CUSTOMERID上建立一個組並選中「在新頁面上啓動每一個組」。而後將Report佈局爲相似於如下內容:
除了CursorAdapter以外,VFP 8還有三個新的基類來改進VFP對XML的支持:XMLAdapter、XMLTable和XMLField。XMLAdapter提供了一種在XML和VFP遊標之間轉換數據的方法。它的功能比CURSORTOXML()和XMLTOCURSOR()函數多得多,包括支持分層XML和使用那些函數不支持的XML類型(如ADO.NET數據集)的功能。XMLTable和XMLField是子對象,它們提供微調XML數據的模式的能力。此外,XMLTable還有一個ApplyDiffgram方法,它容許VFP使用updategrams和diffgrams,這是VFP 7中缺乏的。
爲了讓您瞭解它的功能,我建立了一個返回ADO.NET數據集的ASP.NET Web服務,而後使用VFP中的XMLAdapter對象來使用該數據集。如今我作到了。
首先,在Visual Studio.NET中,我將Northwind Customers表從服務器資源管理器拖到一個名爲NWWebService的新ASP.NET Web服務項目中。這會自動建立兩個對象,SQLConnection1和SQLDataAdapter1。而後,我將如下代碼添加到現有生成的代碼中:
<WebMethod()> Public Function GetAllCustomers() As DataSet Dim loDataSet As New DataSet() Me.SqlConnection1.Open() Me.SqlDataAdapter1.Fill(loDataSet) Return loDataSet End Function
我構建該項目是爲了在NWWebService虛擬目錄(VS.NET自動爲我建立)中生成適當的Web服務文件。
爲了在VFP中使用這個Web服務,我使用IntelliSense管理器註冊了一個名爲「Northwind.NET」的Web服務,指向「http://localhost/NWWebService/NWWebService.asmx?WSDL」做爲WSDL文件的位置。而後我建立了如下代碼(在XMLAdapterWebService.prg中)來調用Web服務並將ADO.NET數據集轉換爲VFP遊標。
local loWS as Northwind.NET, ; loXMLAdapter as XMLAdapter, ; loTable as XMLTable *從.NET Web服務獲取.NET數據集 loWS = NEWOBJECT("Wsclient",HOME()+"ffc\_webservices.vcx") loWS.cWSName = "Northwind.NET" loWS = loWS.SetupClient("http://localhost/NWWebService/NWWebService.asmx" + ; "?WSDL", "NWWebService", "NWWebServiceSoap") loXML = loWS.GetAllCustomers() *建立一個XMLAdapter並加載數據 loXMLAdapter = createobject('XMLAdapter') loXMLAdapter.XMLSchemaLocation = '1' loXMLAdapter.LoadXML(loXML.Item(0).parentnode.xml) *若是成功地加載了XML,那麼從每一個表對象建立並瀏覽一個遊標 if loXMLAdapter.IsLoaded for each loTable in loXMLAdapter.Tables loTable.ToCursor() browse use next loTable endif loXMLAdapter.IsLoaded
注意,爲了使用XMLAdapter,您須要在系統上安裝MSXML 4.0服務包1或更高版本。您能夠從MSDN網站下載(http://MSDN.microsoft.com並搜索MSXML)。
我認爲CursorAdapter是VFP 8中最大和最使人興奮的加強之一,由於它提供了一個一致且易於使用的遠程數據接口,並且它容許咱們建立可重用的數據類。我相信一旦你用它來工做,你會發現他們和我同樣使人興奮。
Doug Hennig是Stonefield Systems Group Inc.的合做夥伴。他是獲獎的Stonefield數據庫工具包(SDT)的做者和獲獎的Stonefield查詢的共同做者。他是《黑客視覺FoxPro 7.0指南》的合著者(與Tamar Granor、Ted Roche和Della Martin一塊兒)和《視覺FoxPro 7.0的新特性》的合著者(與Tamar Granor和Kevin McNeish一塊兒),均來自Hentzenwerke出版社,在Pinnacle Publishing的Pros Talk VisualFoxPro系列中,「VisualFoxPro數據字典」的做者。他在FoxTalk上寫了每個月的「可重用工具」專欄。他是《黑客指南》和《基礎知識》的技術編輯,這兩本書都來自亨森沃克出版社。自1997年以來,道格在每次微軟FoxPro開發者大會(DevCon)以及北美各地的用戶團體和開發者大會上都發表過演講。他是微軟最有價值的專業人士(MVP)和認證專業人士(MCP)。
另文,本文略……