基本介紹
- 中文名:遠程數據服務
- 所屬:遠程數據服務
- 分類:遠程數據服務
- 類別:遠程數據服務

·數據工廠(datafactory)是預設的用於訪問數據存儲的伺服器端組件。它作為伺服器端RDS組件的一部分安裝在計算機上,除了能從數據存儲中獲取數據外,還為伺服器處理髮送到客戶端以及從客戶端傳送來的數據。
· 自定義組件只是一個普通的提供了數據傳送方法的COM組件。當數據工廠不能提供所需的功能時,可以使用自定義組件。本章將介紹一個簡單的組件例子,在本書的後面還有一個更複雜的例子。
Web伺服器使用這兩種組件作為客戶和伺服器數據的接口。
數據源對象的上面是數據綁定管理器,任務是建立HTML控制項與數據源對象的連線。這就是我們所知道的綁定,可以通過設定某些HTML控制項的DATASRC和DATAFLD屬性來實現。下面將對這些內容進行討論,並示範如何在瀏覽器中方便地使用數據。
· 當連線到數據源時,指定數據工廠的模式。這可以指定使用的是哪一個版本的RDS組件,後面將介紹這方面的一個例子。
· RDS數據控制項,用於連線OLE DB數據存儲,能夠指定連線到哪個數據存儲,以及返回哪些數據。
· Java資料庫連線器,這是一個通過Java資料庫控制項(Java DataBase Control,JDBC)連線到數據存儲的Java小程式。這裡我們不想討論JDBC,因為它並不提供其他控制項無法實現的功能。
· 微軟的HTML(MSHTML)數據源對象用HTML標記數據,並把它作為數據源。
· XML數據源對象使用XML數據,用於結構化的或任意結構的XML。
  
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欄位,這樣就可以看到是哪一個欄位更新失敗了。

                     ID="dsoAuthors" WIDTH="0" HEIGHT="0">
  
也可以在客戶端腳本中獲取數據,下面的例子顯示了給TDC載入數據的JScript腳本。
function fillTDC()
{
dsoAuthors.dataURL = 'authors.csv';
dsoAuthors.Reset();
}
如果改變了TDC的DataURL參數,必須使用Reset方法,這樣才能使新的URL起作用。當介紹數據綁定時,會更詳細地討論如何使用它。Reset方法是TDC唯一的一個方法。
類似於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欄位,這樣就可以看到是哪一個欄位更新失敗了。
類似於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();
}
一旦載入了數據,將觸發數據控制項的ondatasetcomplete事件,運行createCells函式。
function createCells()
{
var fldF;
var tblCell;
deleteCells();
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 + '';
tblCell = tblData.rows【1】.insertCell();
tblCell.innerHTML = '';
}
tblData.dataSrc = '#dsoData';
}
這同樣也很簡單。首先刪除了現有的表格單元格(馬上會介紹這個函式),然後遍歷記錄集的欄位。在行頭為每個欄位創建一個新單元格(這個表格只有兩行:第一行,即第0行,是表頭;第二行,即第1行,是表體)。表格單元創建完後,將innerHTML屬性設為對應的欄位名。在表體中創建新單元格的過程類似,但此時使用innerHTML元件保存綁定到數據欄位的INPUT標記。當所有的欄位都完成這樣的操作後,這個表就與數據控制項綁定了。
因為這個頁面允許在兩個不同的數據集之間進行切換,所以需要先刪除現有的數據。
function deleteCells()
{
var iCell;
var iCells;
tblData.dataSrc = '';
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站點上找到。
迄今為止,僅學習了在客戶端如何取到數據,但還沒有涉及如何更新客戶端數據,和將其送回伺服器。別忘了,記錄集是下線的,那么如何更新數據呢?對數據所做的任何修改只是數據控制項中本地記錄的一部分,因此為了更新伺服器必須發一條特殊的指令。然而這並不需做什麼複雜的工作,因為RDS數據控制項有兩個方法,允許我們要么取消最近對數據所做的任何修改,要么將所有修改送到伺服器。
為了方便用戶,可以為此創建一些按鈕。
>Cnacel
SubmitChanges方法只將那些改動過的記錄送回伺服器,而CancelUpdate方法則取消在本地記錄集上所做的任何修改。
更新和取消更新操作並不是唯一所需的。如果想增加新的記錄或刪除一條現有的記錄,怎么辦?可以使用記錄集的AddNew和Delete方法。這將增加或刪除記錄集中的記錄,然後在傳送SubmitChanges命令後,伺服器上的數據就可以被更新。
>Delete
1. 解決衝突的方法
由於與數據源下線,可能會碰到有關衝突的問題。例如在更新一條記錄並將其保存到數據存儲的時候,有人也修改了這條記錄時,會發生什麼情況? SubmitChanges方法已經提供了相應的處理衝突的方法,如果發生衝突,那么該方法將產生一個錯誤。
在調用SubmitChanges方法期間,只要其中一條記錄更新失敗,那么所有的記錄更新都會失敗。這保證了原始數據不會被部分更新。可以遍歷記錄集,並檢測記錄的Status屬性來告訴用戶哪一條記錄更新失敗了。例如,最好調用自己的UpdateData函式,而不只是在命令按鈕中調用SubmitChanges方法。


我們知道記錄有某些形式的衝突,但無法確切地知道為什麼或哪一個欄位引起了衝突。因此需要遍歷欄位檢測它們的值。

欄位有三種值:
Vaule代表新值,即經過修改的欄位值。
UnderlyingVaule代表數據存儲中存儲的欄位值。
OriginalVaule代表從數據存儲讀取後,但還沒有修改之前的欄位值。
這意味著UnderlyingVaule會保存其他用戶修改過的值,而OriginalValue是欄位原有的值。因此比較兩者之值,如果不同,則說明欄位已經被另外的用戶修改了。
可以利用所有這些錯誤信息來創建一個表格以顯示是否確實發生錯誤。例子(RDSConflicts.asp)產生的輸出結果如圖1 0 - 11所示。

使用這種方法,可以看到每一個發生變化的欄位的值。由於SubmitChanges方法可以處理多個欄位,讀者可能希望為這個表增加額外的列以顯示ID欄位,這樣就可以看到是哪一個欄位更新失敗了。