遠程數據服務

遠程數據服務(Remote Data Services,RDS)是允許我們處理客戶端數據的一系列服務的統稱。不用擔心這方面的問題,因為RDS本身就是ADO的一部分,只有在需要傳送和使用客戶端數據時,才會使用。

基本介紹

  • 中文名:遠程數據服務
  • 分類:遠程數據服務
  • 類別:遠程數據服務
遠程數據服務(Remote Data Services,RDS)是允許我們處理客戶端數據的一系列服務的統稱。不用擔心這方面的問題,因為RDS本身就是ADO的一部分,只有在需要傳送和使用客戶端數據時,才會使用。
遠程數據服務RDS允許程式設計師開發原生的WINDOWS分散式多層套用系統,或是開發以瀏覽器為圖形用戶接口的WEB套用系統。
遠程數據服務RDS提供了客戶端應用程式在INTERNET/INTRANET或分散式環境中使用ADO中RECORDSET對象的能力。
可以在瀏覽器中通過遠程數據服務RDS取得RECORDSET對象,然後在腳本語言中存取數據。或在原生WINDOWS應用程式中通過RDS取得RECORDSET對象,然後使用程式代碼來存取遠程數據源中的數據。RDS能夠將ADO取得的數據一DCOM或HTTP通信協定由中介軟體或中介組件傳遞給客戶端,並且把數據快取在客戶端中讓客戶端存取數據。
遠程數據服務RDS和ADO的關係:
程式ADORDSIIS/PWSODBC資料庫.
當我們在程式中試圖使用ADO來存取WEB資料庫時,由於ADO與ODBC分屬於兩台通過Internet連線起來的機器上,因此數據存取方式與ADO,ODBC同屬於一台機器的情況大不相同,為了讓程式也一樣可以利用ADO存取WEB資料庫,於是誕生了RDS,而RDS的角色就象是一位幫ADO存取WEB資料庫的服務員一樣,所以取名“遠程端數據服務”
實際上RDS是由幾個組件構成的。圖10-1說明了這些組件以及它們之間是如何協同工作的。
遠程數據服務
圖10-1 遠程數據服務
組件似乎很多,但並不是所有的組件在每種情形下都被使用,實際上有一些不是RDS的一部分。然而這裡還是把所有可能出現的組件都放在了圖上,以備需要時查看。圖10-1分成了兩部分,因為使用客戶端數據需要一些向客戶端傳送數據的方法,同時數據一旦到達客戶端,也需要一些管理數據的方法。我們先從伺服器端開始。
10.2.1 RDS伺服器組件
雖然RDS用於傳送和訪問客戶端數據,但其確實有一些基於伺服器的組件。這是必需的,因為肯定需要某種方式將數據傳送到客戶端。因此有了一系列能訪問數據並允許傳送數據到客戶端的伺服器組件。我們把實際的數據傳送稱為調度(marshal)。
伺服器端組件圖的最上端是數據存儲,由OLE DB提供者訪問。它並不是RDS的一部分,但這表示只要有相應的OLE DB提供者,就可以通過RDS在客戶端使用任何數據。至於如何處理伺服器上的數據,可以有兩種選擇:
·數據工廠(datafactory)是預設的用於訪問數據存儲的伺服器端組件。它作為伺服器端RDS組件的一部分安裝在計算機上,除了能從數據存儲中獲取數據外,還為伺服器處理髮送到客戶端以及從客戶端傳送來的數據。
· 自定義組件只是一個普通的提供了數據傳送方法的COM組件。當數據工廠不能提供所需的功能時,可以使用自定義組件。本章將介紹一個簡單的組件例子,在本書的後面還有一個更複雜的例子。
Web伺服器使用這兩種組件作為客戶和伺服器數據的接口。
10.2.2 RDS客戶組件
在客戶端先從底端的DataSpace對象開始,該對象作為客戶端的一部分與數據工廠或自定義對象協同工作。DataSpace對象是一個代理對象,負責與伺服器進行通信,同時也是數據傳輸的通道(或者通常所說的調度)。DataSpace對象是用客戶端腳本語言或用HTML語言中的 標記創建的COM對象。在本章後面會看到關於這方面的例子。
DataSpace對象上面是數據源對象(Data Source Object,DSO),負責存儲客戶端數據。一個數據源對象包含一個ADO數據記錄集,與客戶數據快取共同管理數據。客戶數據快取只是一種管理客戶端數據的客戶游標服務。同時數據源對象又是一個COM對象,與DataSpace對象類似,也可以通過客戶端腳本或使用HTML語言中的 標記來創建。同樣,在本章稍後也會介紹關於這方面的一些例子。
數據源對象的上面是數據綁定管理器,任務是建立HTML控制項與數據源對象的連線。這就是我們所知道的綁定,可以通過設定某些HTML控制項的DATASRC和DATAFLD屬性來實現。下面將對這些內容進行討論,並示範如何在瀏覽器中方便地使用數據。
10.2.3 支持RDS的瀏覽器
要知道RDS是微軟的技術,因此只能在微軟的瀏覽器上工作。實際上,只有在IE 4.0或更高版本的瀏覽器中才完全支持RDS。
當編寫依賴於RDS的應用程式時,需要注意訪問應用程式的客戶的RDS版本可能與伺服器端有所不同。舉例來說,IE 4中的是RDS 1.5版本,而IE 5、Office 2000Visual Studio 6中的則是RDS 2.0版本。有兩種方法可以處理這種兼容性問題:
· 確保所有用戶已經升級到RDS的最新版本。如果客戶運行的是Windows 2000,那么已經在運行最新版本的RDS了。否則,可以從網址下載。RDS 2.5版本是最新的隨同Windows 2000一起發布的版本,同時也是一個可單獨下載的軟體包。
· 當連線到數據源時,指定數據工廠的模式。這可以指定使用的是哪一個版本的RDS組件,後面將介紹這方面的一個例子。
10.2.4 數據源對象
數據源對象是一個存儲和管理客戶端數據的客戶端對象。因為這是使用RDS最簡單的一種方式,首先研究一下這些對象。
這裡有幾個不同的數據源對象,每一個都針對不同類型的數據:
· 表格數據控制項(Tabular Data Control,TDC),用於處理表格形式或分隔形式的文本檔案。
· RDS數據控制項,用於連線OLE DB數據存儲,能夠指定連線到哪個數據存儲,以及返回哪些數據。
· Java資料庫連線器,這是一個通過Java資料庫控制項(Java DataBase Control,JDBC)連線到數據存儲的Java小程式。這裡我們不想討論JDBC,因為它並不提供其他控制項無法實現的功能。
· 微軟的HTML(MSHTML)數據源對象用HTML標記數據,並把它作為數據源。
· XML數據源對象使用XML數據,用於結構化的或任意結構的XML。
選用哪一種數據源對象取決於你想做什麼,以及數據從哪裡來。如果需要向客戶提供少量的數據,並且不允許用戶修改數據,那么表格數據控制項(TDC)可能會比較適合。這種數據源是一個文本檔案,不需要任何資料庫,因此編輯起來比較簡單。對於從資料庫中取出數據並且可能需要更新的情況,RDS數據控制項是最合適的。而對於許多新數據源,會發現此時需要使用XML數據控制項。這實際依賴於所使用的Web應用程式的類型,以及用戶所需的功能。
我們將依次介紹這些數據控制項,一旦了解了如何用它們把數據傳送到客戶端,將會介紹如何使用這些數據。
1. 表格數據控制項
表格數據控制項(Tabular Data Control,TDC)是最簡單的數據源對象,主要用於少量的唯讀數據,特別是那些從不改變或很少修改的,不需要從客戶端進行更新的靜態數據。例如,表格數據控制項能提供一個網頁內的選單項或連結的列表。
通過在HTML代碼中使用 標記可以創建一個表格數據控制項。參數DataURL可以指定包含文本數據的檔案名稱。
ID="dsoAuthors" WIDTH="0" HEIGHT="0">
TDC唯讀取表格中的數據或標記為表格形式的數據,例如,可以處理逗號分隔形式的數據(Comma Separated Value, CSV),類似於下面的數據:
"172-32-1176","White","Bob","408 496-7223"
"219-46-8915","Green","Marjorie","415 986-7020"
"238-95-7766","Carson","Cheryl","415 548-7723"
"267-41-2394","O'Leary","Michael","408 286-2428"
"274-80-9391","Straight","Dean","415 834-2919"
"341-22-1782","Smith","Meander","913 843-0462"
"409-56-7008","Bennet","Abraham","415 658-9932"
TDC也可以自由定義。除了DataURL外,TDC還有16個參數,可以通過設定OBJECT標記的參數項或編寫腳本代碼來配置這些參數。參數的說明如表10-1所示:
下面是使用參數創建TDC的一個例子。
ID="dsoAuthors" WIDTH="0" HEIGHT="0">
也可以在客戶端腳本中獲取數據,下面的例子顯示了給TDC載入數據的JScript腳本。
function fillTDC()
{
dsoAuthors.dataURL = 'authors.csv';
dsoAuthors.Reset();
}
如果改變了TDC的DataURL參數,必須使用Reset方法,這樣才能使新的URL起作用。當介紹數據綁定時,會更詳細地討論如何使用它。Reset方法是TDC唯一的一個方法。2. RDS數據控制項RDS數據控制項能夠訪問一般的數據存儲,而不是平面檔案。它通常用於連線SQL資料庫以從表、查詢或存儲過程獲取數據。與TDC不同,RDS數據控制項允許更新數據。在本章稍後通過示例說明如何進行數據更新。
類似於TDC,可以用HTML腳本中的OBJECT標記來創建一個RDS數據控制項,並以類似的方式設定其屬性。
authors
onclick="resetData('publishers')">publishers
下面創建虛表。
這充當了模板的作用。注意,表格中還沒有單元格。這是因為並不知道數據有多少個欄位,所以也將在運行期間創建它們。
編寫JScript代碼。首先看一下resetData函式,該函式設定數據控制項的屬性並載入數據。
function resetData(sTable)
{
// reset the data
dsoData.Connect = 'Provider=SQLOLEDB; Data Source=' +
'' +
'; Initial Catalog=pubs; User ID=sa; Password=';
dsoData.Server = 'http://';
dsoData.SQL = 'SELECT * FROM ' + sTable;
dsoData.Refresh();
}雖然這看起來比使用參數更複雜一些,但是仍然比較簡單。別忘了參數名是如何映射到屬性的?這裡所做的就是設定那些屬性,然後調用Refresh方法更新數據控制項。看上去,這可能比以前的例子更糟糕,因為在代碼中只有不多的ASP,也只是簡單地在屬性中填入Web伺服器的名字。但使用該方法可以在不修改代碼的情況下將此ASP頁面從一個伺服器移到另一個伺服器。作為數據源的表名可以通過選擇適當的按鈕而傳給函式。
一旦載入了數據,將觸發數據控制項的ondatasetcomplete事件,運行createCells函式。
function createCells()
{
var fldF;
var tblCell; // delete what's there already
deleteCells(); // now create the new cells
for (fldF = new enumerator(dsoData.recordset.Fields);
!fldF.atEnd(); fldF.moveNext())
{
// create a new cell for the heading
tblCell = tblData.rows【0】.insertCell();
tblCell.innerHTML = '' + fldF.item().name + ''; // create a new cell for the body
tblCell = tblData.rows【1】.insertCell();
tblCell.innerHTML = '';
} // now bind to the data source
tblData.dataSrc = '#dsoData';
}
這同樣也很簡單。首先刪除了現有的表格單元格(馬上會介紹這個函式),然後遍歷記錄集的欄位。在行頭為每個欄位創建一個新單元格(這個表格只有兩行:第一行,即第0行,是表頭;第二行,即第1行,是表體)。表格單元創建完後,將innerHTML屬性設為對應的欄位名。在表體中創建新單元格的過程類似,但此時使用innerHTML元件保存綁定到數據欄位的INPUT標記。當所有的欄位都完成這樣的操作後,這個表就與數據控制項綁定了。
因為這個頁面允許在兩個不同的數據集之間進行切換,所以需要先刪除現有的數據。
function deleteCells()
{
var iCell;
var iCells; // unbind the table
tblData.dataSrc = ''; // delete existing cells
iCells = tblData.rows【0】.cells.length
for (iCell = 0; iCell < iCells; ++iCell)
{
tblData.rows【0】.deleteCell();
tblData.rows【1】.deleteCell();
}
}
這個子程式只是對表解除綁定,然後在表格中遍歷所有的單元格並刪除它們。等到上述程式執行完畢,表格就只剩下空的表頭和表體行。
這是一個用RDS和一些DHTML實現的簡單例子。可以容易地把其加到一個ASP包含檔案中,並把該檔案放到任何應用程式中,即使數據源不改變也可使用這種方法。
這個例子的全部代碼——檔案RDSDynamicBinding.asp以及類似的其他類型的數據控制項例子,可以在Wrox站點上找到。10.2.6 更新數據
迄今為止,僅學習了在客戶端如何取到數據,但還沒有涉及如何更新客戶端數據,和將其送回伺服器。別忘了,記錄集是下線的,那么如何更新數據呢?對數據所做的任何修改只是數據控制項中本地記錄的一部分,因此為了更新伺服器必須發一條特殊的指令。然而這並不需做什麼複雜的工作,因為RDS數據控制項有兩個方法,允許我們要么取消最近對數據所做的任何修改,要么將所有修改送到伺服器。
為了方便用戶,可以為此創建一些按鈕。
>Cnacel
>Save
SubmitChanges方法只將那些改動過的記錄送回伺服器,而CancelUpdate方法則取消在本地記錄集上所做的任何修改。
更新和取消更新操作並不是唯一所需的。如果想增加新的記錄或刪除一條現有的記錄,怎么辦?可以使用記錄集的AddNew和Delete方法。這將增加或刪除記錄集中的記錄,然後在傳送SubmitChanges命令後,伺服器上的數據就可以被更新。
>Delete
>Add
1. 解決衝突的方法
由於與數據源下線,可能會碰到有關衝突的問題。例如在更新一條記錄並將其保存到數據存儲的時候,有人也修改了這條記錄時,會發生什麼情況? SubmitChanges方法已經提供了相應的處理衝突的方法,如果發生衝突,那么該方法將產生一個錯誤。
在調用SubmitChanges方法期間,只要其中一條記錄更新失敗,那么所有的記錄更新都會失敗。這保證了原始數據不會被部分更新。可以遍歷記錄集,並檢測記錄的Status屬性來告訴用戶哪一條記錄更新失敗了。例如,最好調用自己的UpdateData函式,而不只是在命令按鈕中調用SubmitChanges方法。 此時,我們知道已經發生了一個錯誤,但並不知道是哪一個錯誤,因此必須重新同步當前數據與數據存儲中的數據。使用adResyncUnderlyingValues確保只有欄位的UnderlyingValues屬性被數據存儲中的值覆蓋,也就是說所做的修改是安全的(記住,修改的內容保存在Value屬性中)。可以在後面的代碼中比較當前的值與資料庫中的值。 Status可以是不同值的組合,詳見附錄。例子代碼( RDSConflicts.asp )中有一個將這些值轉換為描述性字元串的函式。
我們知道記錄有某些形式的衝突,但無法確切地知道為什麼或哪一個欄位引起了衝突。因此需要遍歷欄位檢測它們的值。 這就是UnderlyingVaule屬性發揮作用的地方。
欄位有三種值:
Vaule代表新值,即經過修改的欄位值。
UnderlyingVaule代表數據存儲中存儲的欄位值。
OriginalVaule代表從數據存儲讀取後,但還沒有修改之前的欄位值。
這意味著UnderlyingVaule會保存其他用戶修改過的值,而OriginalValue是欄位原有的值。因此比較兩者之值,如果不同,則說明欄位已經被另外的用戶修改了。
可以利用所有這些錯誤信息來創建一個表格以顯示是否確實發生錯誤。例子(RDSConflicts.asp)產生的輸出結果如圖1 0 - 11所示。 這裡可以見到三種不同的值。原始值是Johnson。然後,在另一個視窗(如SQL Server Query Analyzer)中將值改為Johnson。在瀏覽器視窗,利用RDS將這個值改為Andy,並按下Save All Changes按鈕。Resync命令將資料庫中的值取出並寫入UnderlyingVaule屬性。我也對Lastname列做了相似的修改。
使用這種方法,可以看到每一個發生變化的欄位的值。由於SubmitChanges方法可以處理多個欄位,讀者可能希望為這個表增加額外的列以顯示ID欄位,這樣就可以看到是哪一個欄位更新失敗了。
遠程數據服務
圖1 0 - 11 遠程數據服務
下面是使用參數創建TDC的一個例子。
ID="dsoAuthors" WIDTH="0" HEIGHT="0">
也可以在客戶端腳本中獲取數據,下面的例子顯示了給TDC載入數據的JScript腳本。
function fillTDC()
{
dsoAuthors.dataURL = 'authors.csv';
dsoAuthors.Reset();
}
如果改變了TDC的DataURL參數,必須使用Reset方法,這樣才能使新的URL起作用。當介紹數據綁定時,會更詳細地討論如何使用它。Reset方法是TDC唯一的一個方法。
2. RDS數據控制項RDS數據控制項能夠訪問一般的數據存儲,而不是平面檔案。它通常用於連線SQL資料庫以從表、查詢或存儲過程獲取數據。與TDC不同,RDS數據控制項允許更新數據。在本章稍後通過示例說明如何進行數據更新。
類似於TDC,可以用HTML腳本中的OBJECT標記來創建一個RDS數據控制項,並以類似的方式設定其屬性。
authors
onclick="resetData('publishers')">publishers
下面創建虛表。
這充當了模板的作用。注意,表格中還沒有單元格。這是因為並不知道數據有多少個欄位,所以也將在運行期間創建它們。
編寫JScript代碼。首先看一下resetData函式,該函式設定數據控制項的屬性並載入數據。
function resetData(sTable)
{
// reset the data
dsoData.Connect = 'Provider=SQLOLEDB; Data Source=' +
'' +
'; Initial Catalog=pubs; User ID=sa; Password=';
dsoData.Server = 'http://';
dsoData.SQL = 'SELECT * FROM ' + sTable;
dsoData.Refresh();
}雖然這看起來比使用參數更複雜一些,但是仍然比較簡單。別忘了參數名是如何映射到屬性的?這裡所做的就是設定那些屬性,然後調用Refresh方法更新數據控制項。看上去,這可能比以前的例子更糟糕,因為在代碼中只有不多的ASP,也只是簡單地在屬性中填入Web伺服器的名字。但使用該方法可以在不修改代碼的情況下將此ASP頁面從一個伺服器移到另一個伺服器。作為數據源的表名可以通過選擇適當的按鈕而傳給函式。
一旦載入了數據,將觸發數據控制項的ondatasetcomplete事件,運行createCells函式。
function createCells()
{
var fldF;
var tblCell; // delete what's there already
deleteCells(); // now create the new cells
for (fldF = new enumerator(dsoData.recordset.Fields);
!fldF.atEnd(); fldF.moveNext())
{
// create a new cell for the heading
tblCell = tblData.rows【0】.insertCell();
tblCell.innerHTML = '' + fldF.item().name + ''; // create a new cell for the body
tblCell = tblData.rows【1】.insertCell();
tblCell.innerHTML = '';
} // now bind to the data source
tblData.dataSrc = '#dsoData';
}
這同樣也很簡單。首先刪除了現有的表格單元格(馬上會介紹這個函式),然後遍歷記錄集的欄位。在行頭為每個欄位創建一個新單元格(這個表格只有兩行:第一行,即第0行,是表頭;第二行,即第1行,是表體)。表格單元創建完後,將innerHTML屬性設為對應的欄位名。在表體中創建新單元格的過程類似,但此時使用innerHTML元件保存綁定到數據欄位的INPUT標記。當所有的欄位都完成這樣的操作後,這個表就與數據控制項綁定了。
因為這個頁面允許在兩個不同的數據集之間進行切換,所以需要先刪除現有的數據。
function deleteCells()
{
var iCell;
var iCells; // unbind the table
tblData.dataSrc = ''; // delete existing cells
iCells = tblData.rows【0】.cells.length
for (iCell = 0; iCell < iCells; ++iCell)
{
tblData.rows【0】.deleteCell();
tblData.rows【1】.deleteCell();
}
}
這個子程式只是對表解除綁定,然後在表格中遍歷所有的單元格並刪除它們。等到上述程式執行完畢,表格就只剩下空的表頭和表體行。
這是一個用RDS和一些DHTML實現的簡單例子。可以容易地把其加到一個ASP包含檔案中,並把該檔案放到任何應用程式中,即使數據源不改變也可使用這種方法。
這個例子的全部代碼——檔案RDSDynamicBinding.asp以及類似的其他類型的數據控制項例子,可以在Wrox站點上找到。10.2.6 更新數據
迄今為止,僅學習了在客戶端如何取到數據,但還沒有涉及如何更新客戶端數據,和將其送回伺服器。別忘了,記錄集是下線的,那么如何更新數據呢?對數據所做的任何修改只是數據控制項中本地記錄的一部分,因此為了更新伺服器必須發一條特殊的指令。然而這並不需做什麼複雜的工作,因為RDS數據控制項有兩個方法,允許我們要么取消最近對數據所做的任何修改,要么將所有修改送到伺服器。
為了方便用戶,可以為此創建一些按鈕。
>Cnacel
>Save
SubmitChanges方法只將那些改動過的記錄送回伺服器,而CancelUpdate方法則取消在本地記錄集上所做的任何修改。
更新和取消更新操作並不是唯一所需的。如果想增加新的記錄或刪除一條現有的記錄,怎么辦?可以使用記錄集的AddNew和Delete方法。這將增加或刪除記錄集中的記錄,然後在傳送SubmitChanges命令後,伺服器上的數據就可以被更新。
>Delete
>Add
1. 解決衝突的方法
由於與數據源下線,可能會碰到有關衝突的問題。例如在更新一條記錄並將其保存到數據存儲的時候,有人也修改了這條記錄時,會發生什麼情況? SubmitChanges方法已經提供了相應的處理衝突的方法,如果發生衝突,那么該方法將產生一個錯誤。
在調用SubmitChanges方法期間,只要其中一條記錄更新失敗,那么所有的記錄更新都會失敗。這保證了原始數據不會被部分更新。可以遍歷記錄集,並檢測記錄的Status屬性來告訴用戶哪一條記錄更新失敗了。例如,最好調用自己的UpdateData函式,而不只是在命令按鈕中調用SubmitChanges方法。 此時,我們知道已經發生了一個錯誤,但並不知道是哪一個錯誤,因此必須重新同步當前數據與數據存儲中的數據。使用adResyncUnderlyingValues確保只有欄位的UnderlyingValues屬性被數據存儲中的值覆蓋,也就是說所做的修改是安全的(記住,修改的內容保存在Value屬性中)。可以在後面的代碼中比較當前的值與資料庫中的值。 Status可以是不同值的組合,詳見附錄。例子代碼( RDSConflicts.asp )中有一個將這些值轉換為描述性字元串的函式。
我們知道記錄有某些形式的衝突,但無法確切地知道為什麼或哪一個欄位引起了衝突。因此需要遍歷欄位檢測它們的值。 這就是UnderlyingVaule屬性發揮作用的地方。
欄位有三種值:
Vaule代表新值,即經過修改的欄位值。
UnderlyingVaule代表數據存儲中存儲的欄位值。
OriginalVaule代表從數據存儲讀取後,但還沒有修改之前的欄位值。
這意味著UnderlyingVaule會保存其他用戶修改過的值,而OriginalValue是欄位原有的值。因此比較兩者之值,如果不同,則說明欄位已經被另外的用戶修改了。
可以利用所有這些錯誤信息來創建一個表格以顯示是否確實發生錯誤。例子(RDSConflicts.asp)產生的輸出結果如圖1 0 - 11所示。 這裡可以見到三種不同的值。原始值是Johnson。然後,在另一個視窗(如SQL Server Query Analyzer)中將值改為Johnson。在瀏覽器視窗,利用RDS將這個值改為Andy,並按下Save All Changes按鈕。Resync命令將資料庫中的值取出並寫入UnderlyingVaule屬性。我也對Lastname列做了相似的修改。
使用這種方法,可以看到每一個發生變化的欄位的值。由於SubmitChanges方法可以處理多個欄位,讀者可能希望為這個表增加額外的列以顯示ID欄位,這樣就可以看到是哪一個欄位更新失敗了。
2. RDS數據控制項
RDS數據控制項能夠訪問一般的數據存儲,而不是平面檔案。它通常用於連線SQL資料庫以從表、查詢或存儲過程獲取數據。與TDC不同,RDS數據控制項允許更新數據。在本章稍後通過示例說明如何進行數據更新。
類似於TDC,可以用HTML腳本中的OBJECT標記來創建一個RDS數據控制項,並以類似的方式設定其屬性。
authors
onclick="resetData('publishers')">publishers
下面創建虛表。
這充當了模板的作用。注意,表格中還沒有單元格。這是因為並不知道數據有多少個欄位,所以也將在運行期間創建它們。
編寫JScript代碼。首先看一下resetData函式,該函式設定數據控制項的屬性並載入數據。
function resetData(sTable)
{
// reset the data
dsoData.Connect = 'Provider=SQLOLEDB; Data Source=' +
'' +
'; Initial Catalog=pubs; User ID=sa; Password=';
dsoData.Server = 'http://';
dsoData.SQL = 'SELECT * FROM ' + sTable;
dsoData.Refresh();
}
雖然這看起來比使用參數更複雜一些,但是仍然比較簡單。別忘了參數名是如何映射到屬性的?這裡所做的就是設定那些屬性,然後調用Refresh方法更新數據控制項。看上去,這可能比以前的例子更糟糕,因為在代碼中只有不多的ASP,也只是簡單地在屬性中填入Web伺服器的名字。但使用該方法可以在不修改代碼的情況下將此ASP頁面從一個伺服器移到另一個伺服器。作為數據源的表名可以通過選擇適當的按鈕而傳給函式。
一旦載入了數據,將觸發數據控制項的ondatasetcomplete事件,運行createCells函式。
function createCells()
{
var fldF;
var tblCell;
// delete what's there already
deleteCells();
// now create the new cells
for (fldF = new enumerator(dsoData.recordset.Fields);
!fldF.atEnd(); fldF.moveNext())
{
// create a new cell for the heading
tblCell = tblData.rows【0】.insertCell();
tblCell.innerHTML = '' + fldF.item().name + '';
// create a new cell for the body
tblCell = tblData.rows【1】.insertCell();
tblCell.innerHTML = '';
}
// now bind to the data source
tblData.dataSrc = '#dsoData';
}
這同樣也很簡單。首先刪除了現有的表格單元格(馬上會介紹這個函式),然後遍歷記錄集的欄位。在行頭為每個欄位創建一個新單元格(這個表格只有兩行:第一行,即第0行,是表頭;第二行,即第1行,是表體)。表格單元創建完後,將innerHTML屬性設為對應的欄位名。在表體中創建新單元格的過程類似,但此時使用innerHTML元件保存綁定到數據欄位的INPUT標記。當所有的欄位都完成這樣的操作後,這個表就與數據控制項綁定了。
因為這個頁面允許在兩個不同的數據集之間進行切換,所以需要先刪除現有的數據。
function deleteCells()
{
var iCell;
var iCells;
// unbind the table
tblData.dataSrc = '';
// delete existing cells
iCells = tblData.rows【0】.cells.length
for (iCell = 0; iCell < iCells; ++iCell)
{
tblData.rows【0】.deleteCell();
tblData.rows【1】.deleteCell();
}
}
這個子程式只是對表解除綁定,然後在表格中遍歷所有的單元格並刪除它們。等到上述程式執行完畢,表格就只剩下空的表頭和表體行。
這是一個用RDS和一些DHTML實現的簡單例子。可以容易地把其加到一個ASP包含檔案中,並把該檔案放到任何應用程式中,即使數據源不改變也可使用這種方法。
這個例子的全部代碼——檔案RDSDynamicBinding.asp以及類似的其他類型的數據控制項例子,可以在Wrox站點上找到。
10.2.6 更新數據
迄今為止,僅學習了在客戶端如何取到數據,但還沒有涉及如何更新客戶端數據,和將其送回伺服器。別忘了,記錄集是下線的,那么如何更新數據呢?對數據所做的任何修改只是數據控制項中本地記錄的一部分,因此為了更新伺服器必須發一條特殊的指令。然而這並不需做什麼複雜的工作,因為RDS數據控制項有兩個方法,允許我們要么取消最近對數據所做的任何修改,要么將所有修改送到伺服器。
為了方便用戶,可以為此創建一些按鈕。
>Cnacel
>Save
SubmitChanges方法只將那些改動過的記錄送回伺服器,而CancelUpdate方法則取消在本地記錄集上所做的任何修改。
更新和取消更新操作並不是唯一所需的。如果想增加新的記錄或刪除一條現有的記錄,怎么辦?可以使用記錄集的AddNew和Delete方法。這將增加或刪除記錄集中的記錄,然後在傳送SubmitChanges命令後,伺服器上的數據就可以被更新。
>Delete
>Add
1. 解決衝突的方法
由於與數據源下線,可能會碰到有關衝突的問題。例如在更新一條記錄並將其保存到數據存儲的時候,有人也修改了這條記錄時,會發生什麼情況? SubmitChanges方法已經提供了相應的處理衝突的方法,如果發生衝突,那么該方法將產生一個錯誤。
在調用SubmitChanges方法期間,只要其中一條記錄更新失敗,那么所有的記錄更新都會失敗。這保證了原始數據不會被部分更新。可以遍歷記錄集,並檢測記錄的Status屬性來告訴用戶哪一條記錄更新失敗了。例如,最好調用自己的UpdateData函式,而不只是在命令按鈕中調用SubmitChanges方法。
遠程數據服務
遠程數據服務
此時,我們知道已經發生了一個錯誤,但並不知道是哪一個錯誤,因此必須重新同步當前數據與數據存儲中的數據。使用adResyncUnderlyingValues確保只有欄位的UnderlyingValues屬性被數據存儲中的值覆蓋,也就是說所做的修改是安全的(記住,修改的內容保存在Value屬性中)。可以在後面的代碼中比較當前的值與資料庫中的值。
遠程數據服務
遠程數據服務
Status可以是不同值的組合,詳見附錄。例子代碼( RDSConflicts.asp )中有一個將這些值轉換為描述性字元串的函式。
我們知道記錄有某些形式的衝突,但無法確切地知道為什麼或哪一個欄位引起了衝突。因此需要遍歷欄位檢測它們的值。
遠程數據服務
遠程數據服務
這就是UnderlyingVaule屬性發揮作用的地方。
欄位有三種值:
Vaule代表新值,即經過修改的欄位值。
UnderlyingVaule代表數據存儲中存儲的欄位值。
OriginalVaule代表從數據存儲讀取後,但還沒有修改之前的欄位值。
這意味著UnderlyingVaule會保存其他用戶修改過的值,而OriginalValue是欄位原有的值。因此比較兩者之值,如果不同,則說明欄位已經被另外的用戶修改了。
可以利用所有這些錯誤信息來創建一個表格以顯示是否確實發生錯誤。例子(RDSConflicts.asp)產生的輸出結果如圖1 0 - 11所示。
遠程數據服務
圖1 0 - 11 遠程數據服務
這裡可以見到三種不同的值。原始值是Johnson。然後,在另一個視窗(如SQL Server Query Analyzer)中將值改為Johnson。在瀏覽器視窗,利用RDS將這個值改為Andy,並按下Save All Changes按鈕。Resync命令將資料庫中的值取出並寫入UnderlyingVaule屬性。我也對Lastname列做了相似的修改。
使用這種方法,可以看到每一個發生變化的欄位的值。由於SubmitChanges方法可以處理多個欄位,讀者可能希望為這個表增加額外的列以顯示ID欄位,這樣就可以看到是哪一個欄位更新失敗了。

相關詞條

熱門詞條

聯絡我們