亚洲免费在线-亚洲免费在线播放-亚洲免费在线观看-亚洲免费在线观看视频-亚洲免费在线看-亚洲免费在线视频

ADO在.NET應用程序中揮灑自如

系統 2004 0

ADO 在 .NET 應用程序中揮灑自如

發布日期: 4/1/2004 | 更新日期: 4/1/2004

Dino Esposito

2001 年 2 月 22 日

下載 Data02222001.exe

*

軟件地質學家聲稱這種巖石起源于后 Internet 時代,即在第一次 ODBC 冰河期后出現。在過去的數年時間里建立的所有 DNA 系統中,都多次發現了這種礦石代碼 — 在這段時間里,無疑存在地質學時代的軟件雛形。

了解 ADO 巖石的形成過程有助于獲得有關上一個軟件時代中的周圍環境和業務邏輯的有用信息。推斷過去并了解其促成因素始終是一種判斷如何規劃和面向未來的有效方法。

這種基本的哲學原則在翻譯為軟件術語后,就成了一條人們耳熟能詳的警示:“做好管理您的遺傳代碼的準備。”(我們所有人都有某些種類的遺傳代碼,因此,至少在沒有翻箱倒柜地進行仔細查找之前不要斷言您沒有遺傳代碼。)

從 .NET 應用程序的觀點來看,所有 ADO 代碼都是遺傳代碼。事實上,要在 .NET 中完成數據處理,您應該使用新的 ADO.NET 類。如果您剪切和粘貼使用 ADO 對象的現有 Visual Basic_ 或 ASP 應用程序,并將它保存為 .NET 等效應用程序,則一定會出現許多錯誤,對此,您一定要有心理準備。

簡而言之,您可以將 ADO 類導入到任何類別的 .NET 應用程序(Windows 窗體、Web 窗體或 Web 服務)或者將其替換為 ADO.NET。問題難就難在,人們將 ADO.NET 看成是基于 Web 的下一級 ADO。然而,它在功能上并不等同于 ADO,但也不是與 ADO 完全無關。

正如您所看到的一樣,這會產生許多重要的設計問題,其中最重要的無疑是在 .NET 應用程序中如何集成 ADO。第二點(但絕非不重要)是找出 ADO.NET 和 ADO 在功能上的差異,以及因而為在兩個框架中獲得相同結果而應采取的措施。

本期將設法詳細解答這些問題。換句話說,此處,我最大目的是描述一些基本的規則,以預測在您以后的一些項目中可能出現的代碼地震或功能冰河。

在穿越 COM 河流的過程中架起了一座 Interop 的橋梁(此外,需要修改樣式)

對于所有 .NET 應用程序,ADO 就是一個外部組件,即各種組件模型的子模型。對于所有 .NET 應用程序,調用 ADO 對象與調用任何其他 COM(+) 組件絕無兩樣。所有 .NET 應用程序必須執行一些非常規的操作來調用 COM(+) 組件。在 nutshell 中,ADO 在 .NET 領域是一個不折不扣的門外漢。

另一方面,.NET 框架只不過是在不斷發展的組件結構中向前邁出的自然而然的一步,這種結構是 COM 在數年前創立的。盡管 COM 和 .NET 有很多共同之處(包括組件重復使用和語言中立性),但兩者仍是差別很大的實體。要從其中一個實體調用另一個實體,需要搭建特殊的橋梁來保證兼容性。

COM Interop 模塊提供了從 .NET 應用程序訪問現有 COM 組件所需的中間代碼層。它作為本地代理,并負責將 COM 組件公開為本機 .NET 類。更為重要的是,它執行此操作時不需要修改原始組件。

為將現有的 COM 組件加入到 .NET 托管應用程序中,您可以通過系統提供的特殊實用程序(稱為 TLBIMP)導入組件的類型庫。它為 .NET 應用程序提供一個與 COM 對象具有相同編程接口的新框架類。完成此操作后,調用 COM 對象就像調用本機 .NET 類一樣。

如何導入 ADO

TLBIMP.EXE 是 .NET 框架提供的一個免費系統實用程序。它生成一個程序集,其中包含基于指定 COM 類型庫的常規 .NET 元數據。(存在類型庫是完成此操作的必要條件。)

因此,要將 ADO 對象類型導入到 .NET,您需要按如下方式操作:

    tlbimp.exe msado15.dll

  

msado15.dll 中包含對象的整個 ADO 層次結構,該文件通常安裝在 c:/program files/common files/system/ado 文件夾中。在這種情況下,TLBIMP 在當前文件夾中創建一個名為 adodb.dll 的文件。除非您指定一個輸出文件名,否則該實用程序將使用庫的名稱。您可以在命令行中使用 /out:name 開關設置輸出名稱。

如果您使用 Visual Studio .NET 來生成 .NET 應用程序,您甚至不需要了解 TLBIMP。在這種情況下,在解決方案資源管理器中右鍵單擊“引用”節點,并從提供的已注冊的 COM 組件列表中選取 ADO 庫即可。

在完成此操作后,就可以在 .NET 代碼中將 ADO 對象作為本機類使用。對于從 SQL Server 表提取某些記錄并通過列表視圖對它們進行顯示的典型 Visual Basic 應用程序,現在可以使用 C# 進行重寫,如下所示:

    String conn = "PROVIDER=SQLOLEDB;INITIAL CATALOG=Northwind;" + 
              "SERVER=localhost;UID=sa;PWD=;";
String cmd = "SELECT firstname, lastname FROM Employees";

ADODB.Recordset adoRS = new ADODB.Recordset();
adoRS.Open(cmd, conn, ADODB.CursorTypeEnum.adOpenForwardOnly,
      ADODB.LockTypeEnum.adLockReadOnly, 0);
         
while (!adoRS.EOF) {
   listView1.ListItems.Add(adoRS.Fields["lastname"].Value + 
         ", " + 
         adoRS.Fields["firstname"].Value);
         adoRS.MoveNext();         
}

  

此處的關鍵在于,在代碼需要新的 ADODB.Recordset 對象實例時,會發生什么情況。您在下面看到的 Windows 窗體應用程序是一個 .NET 客戶端,表面上看來該客戶端是在創建一個 ADO 記錄集 COM 對象實例。然而,在內部所發生的情況卻略有不同。

data02222001-fig1.gif

圖 1. 使用 ADO 提取數據的 Windows 窗體應用程序

客戶端仍然與一個常規 .NET 類通信,該類稱為運行庫可調用包裝類 (RCW),其工作方式就像原始 Recordset 對象一樣。在創建 RCW 類時,它立即實例化目標組件。然后,RCW 類的工作方式就像未托管組件的某種代理一樣。

未托管對象與其 .NET 版本類具有一對一的關系。不同 COM 組件實例是通過不同 RCW 類管理的,但沒有使用新的 RCW 對相同實例進行額外的引用。

RCW 基礎結構負責在托管代碼和非托管代碼之間封送方法參數和返回值。當然,僅當 COM 和 .NET 中的數據表示形式不同時,才會進行這種類型的轉換。例如,BSTR 變量必須變為字符串變量,反之亦然。

COM 和 .NET 在很多方面是不同的,這些方面包括異常處理、內存管理、函數標識和線程處理等等。RCW 層必須以某種方式隱藏所有這些差異,以使連接的每一端(RCW 類和 COM 對象)看到它知道如何使用的編程接口和環境。

COM 客戶端應該直接控制它們所實例化的對象的生命周期。相反,.NET 客戶端知道系統垃圾回收器將隨后清理內存。RCW 類(TLBIMP 在所生成的程序集中對其進行硬編碼)是從知道如何處理此差異的基類繼承的。

類似地,.NET 應用程序應該以線程安全的方式公開共享資源。而 COM 客戶端應該知道服務器組件支持的線程模型。需要重申的是,RCW 類負責在正確類型的單元內實例化目標 COM 對象。

COM 對象通過 HRESULT 返回代碼返回成功或失敗,而 .NET 客戶端從引發的異常了解到其調用出現了錯誤。RCW 則將其遇到的任何失敗的 HRESULT 值都轉換為 .NET 異常。(因此,應該避免使用通過 HRESULT 返回提示性信息內容的 COM 對象。)

現在我們應該清楚以下事實:從 .NET 客戶端調用 ADO 對象是可行的,并且并不是特別費事。但是,每次從 .NET 上下文中調用 COM 服務器對象時,將在您的應用程序和實際對象之間不知不覺地插入大量代碼。您與看不見的代理進行通信,該代理又進而詢問 COM 對象,而使您看不到 COM 和 .NET 之間的結構差異。

代理給您造成快速而方便地進行通信的錯覺。實際上,每次您調用它時,都要在波濤洶涌的水上搭建一座橋梁。計算此過程的實際工作量完全在于您自己,并且取決于您的項目。

這種系統開銷只影響通信信道,可通過此信道在 .NET 客戶端和 COM 組件之間傳遞請求和響應。如果 COM 組件又調用其他 COM 對象(例如,使用 ADO 或 ATL COM 使用者調用 OLE DB 提供程序的 Visual Basic 數據訪問組件),則不需要進一步進行處理。

COM Interop 層的開銷是由于在 .NET 島和 COM 陸地之間搭建橋梁造成的。因此,您只支付一次全價。訪問 ADO 的 .NET 客戶端執行相同的操作,無論它是直接調用 ADO 對象模型,還是向下調用不同的數據訪問組件。

在 .NET 中使用記錄集

如果您使用 ADO,則最終要用到 Recordset 對象。但是,ADO.NET 中沒有此類對象。這本身并不是什么問題,只要您知道正在做什么就行了,即,堅持使用一種過時的編程模型。

隨著時間的推移, Recordset 對象發生了很大變化。最初,它只是 COM 版本的 ODBC resultset 而已,并增加了一些非常有用的功能(例如,書簽、篩選和排序)。從 ADO 2.6 起, Recordset 支持流、XML 持久性、批處理更新、數據斷開、手動構造和數據構形等等。

盡管提供了這么多功能, Recordset 并未提供處理多個數據表的功能,或者使用存儲過程和自定義命令來批處理更新數據源。此外, Recordset 是一個 COM 對象,它很難與其他在非 Windows 平臺上運行的模塊進行交換。再者,如果您要將記錄集與其他在基于 Windows 的平臺上運行的不同模塊進行交換,您必須在 COM 封送和類型轉換層完成大量的工作。

為提高整個數據處理子系統的互操作性和可伸縮性,.NET 推出了一種以數據為中心的新數據模型,它與 ADO 和 OLE DB 以數據庫為中心的標準模型相反。從以下三個重要變化就可以清楚地看到這一點:

?

將 ADO Recordset 的功能分成不同的且更加簡單的對象。

?

引入了通用的數據容器對象,即 DataSet

?

DataSet 對象中嵌入了 XML 數據表示形式,從基本上講,就是合并了兩種編程接口(關系型和分層型)。

套用愛因斯坦的話說,.NET 試圖使數據訪問盡可能簡單(和輕便),但同時又具有足夠高的可靠性和強大的功能以滿足最苛刻的要求。與 ADO 相比,ADO.NET 的對象模型設計是一個重大的轉變。ADO.NET 并不是像 Recordset 那樣龐大且相當單一的對象,它是一組更簡單、更加專用的對象。“專用與多功能性”就是軟件在日常生活中遇到的另一個雙重矛盾。

可以在 DataTable 對象中找到 .NET 版本的 Recordset 對象。即使 DataTable 僅實現了 Recordset 的基本功能(必須處理數據讀取和寫入的功能),這種說法也站得住腳。

在 .NET 中,目前的 ADO 代碼使用的 Recordset 所遵循的原則不再有效。這意味著,很難將 Recordset 與典型 .NET 應用程序的其他元素集成在一起。例如,您不能使用 Recordset 填充 ASP.NET 或 Windows 窗體數據網格。

而您能做的就是將 Recordset 轉換為 .NET 數據容器類。以下代碼片段使用先前生成的 Recordset ,并建立等效的 DataTable

    DataTable dt = new DataTable("AdaptedFromRecordset");
dt.Columns.Add ("EmployeeName", System.Type.GetType("System.String"));
while (!adoRS.EOF) {
DataRow dr;
   dr = dt.NewRow();
   dr["EmployeeName"] = adoRS.Fields["lastname"].Value + 
", " + 
adoRS.Fields["firstname"].Value;

   dt.Rows.Add (dr); 
   adoRS.MoveNext();         
}
dataGrid1.DataSource = dt.DefaultView;

  

正如以下函數所顯示的那樣,可以將此代碼方便地推廣到任何記錄集:

    DataTable RecordsetToDataTable(ADODB.Recordset adoRS, String strTable)
{
// Assumes the recordset is open and moves on the first record
   adoRS.MoveFirst();
   DataTable dt = new DataTable(strTable);

   // Loops through the Recordset's fields
for(int i=0; i < adoRS.Fields.Count; i++) {
      String strColName = adoRS.Fields[i].Name;
   Type t = adoRS.Fields[i].Value.GetType();
   dt.Columns.Add (strColName, t);       
}

   // Loops through records and columns
   while (!adoRS.EOF) {
      DataRow dr = dt.NewRow();
      for(int i=0; i < adoRS.Fields.Count; i++) 
         dr[i] = adoRS.Fields[i].Value;
      
      dt.Rows.Add (dr); 
      adoRS.MoveNext();         
}

   // Leaves the recordset on the last record
   return dt;
}

  

該代碼首先滾動 Recordset 字段集合,然后將列添加到新創建的 DataTable 對象中。新列保留了 ADO 字段的名稱,并且系統給其指定了等效的 .NET 類型。

    Type t = adoRS.Fields[i].Value.GetType();

  

注意,RCW 引擎對 Recordset Field 對象的原始接口進行了一定的修改。它添加了返回 .NET System.Type 對象的 GetType 方法。ADO Field 對象中沒有此類方法。

下一步,該函數遍歷記錄并填充 DataTable 行集合。

您可以按以下方式使用此 DataTable 對象:

    DataTable dt = RecordsetToDataTable(adoRS, "AdaptedFromRecordset");
dataGrid1.DataSource = dt.DefaultView;

  

如果您打算搭建一座橋梁,使現有 ADO 代碼無縫地流入您的 .NET 應用程序中,則做好準備將這座橋梁向前延伸,從 ADO 對象一直連接到類似的 ADO.NET 對象。

使用函數來隱藏將 ADO 和 ADO.NET 對象無縫地集成在一起所需的額外代碼簡直就是面向對象的工作。一種更為完善的解決方案是,設置一種從 DataTable 繼承并添加了兩種新的構造函數的 AdoDataTable 類。此外:

    public DataTable();
public DataTable(String);

  

它還具有以下優點:

    public DataTable(ADODB.Recordset);
public DataTable(ADODB.Recordset, String);

  

前者將使用默認的表名稱,而后者將使用指定的名稱。該類的源代碼類似于:

    using System;
using System.Data;
public class AdoDataTable : System.Data.DataTable
{
public AdoDataTable(ADODB.Recordset adoRS)
   { RecordsetToDataTable(adoRS, "MyNewTable"); }

public AdoDataTable(ADODB.Recordset adoRS, String strTableName)   
{ RecordsetToDataTable(adoRS, strTableName);   }

private void RecordsetToDataTable(ADODB.Recordset adoRS, 
String strTable)
{
      // Assumes the recordset is open
   adoRS.MoveFirst();

      // Loops through the Recordset's fields
   for(int i=0; i < adoRS.Fields.Count; i++)   {
         String strColName = adoRS.Fields[i].Name;
         Type t = adoRS.Fields[i].Value.GetType();
      Columns.Add (strColName, t);       
      }
         
      // Loops through the Recordset's records to populate the DataTable
      while (!adoRS.EOF)   {
         DataRow dr;
         dr = NewRow();

         for(int i=0; i < adoRS.Fields.Count; i++)   
            dr[i] = adoRS.Fields[i].Value;
            
         Rows.Add (dr); 
         adoRS.MoveNext();         
      }

      // Leaves the recordset on the last record
   }
}

  

.NET 應用程序只需在項目中引用此類,并使用以下極其簡單的代碼便可獲取與以前相同的結果:

    AdoDataTable adt = new AdoDataTable(adoRS, "AdaptedFromRecordset"); 
dataGrid1.DataSource = adt.DefaultView;

  

在編寫該類時,要在每種方法之前添加此特殊的注釋:

    /// <summary>
///    Comment here
/// </summary>

  

Visual Studio .NET 將使用此文本來提供免費的 IntelliSense 支持。

一般來說, Recordset 可幫助您逐步遷移到 .NET,但您越早遷移到 ADO.NET,您的遷移過程的效果就會越好。正如我在上一期專欄中所說的一樣,一旦您選擇了 .NET,您便沒有兩全的辦法。要么保持系統不變,要么從頭開始重新考慮該系統,并制訂中期或長期的遷移計劃。

服務器游標

從 Beta 1 起,ADO.NET 不再直接支持以下數據庫編程功能:服務器游標。如果您需要在代碼中使用服務器游標,則必須借助于 ADO 功能來實現。

ADO.NET 是設計用來滿足大多數要求的。此原則要求小組將設計重點放在中斷連接的數據訪問和客戶端游標上,而不是放在可伸縮性差的(但有時是必需的)服務器端游標上。

服務器游標始終需要打開的連接,它代表了源于過去客戶機/服務器計算的設計方法。雖然現在仍存在許多只能使用服務器游標的應用程序,但基于 Web 的系統根本不需要它們。

因此,如果當前代碼使用服務器游標,您應該怎么辦呢?要做的第一件事就是,慎重考慮是否選擇放棄動態的服務器端游標而使用靜態的客戶端游標,靜態的客戶端游標是 ADO.NET 編程接口中首選和推薦的游標。

如果您不能更改代碼以使用客戶端游標,請繼續使用 ADO。

它是否會揮灑自如?

在 .NET 應用程序中使用 ADO 并不是非常困難的事。但是,這是一種短期方法,因為它破壞了 .NET 類的完整性。它使您(勇敢的 .NET 開發人員)被迫使用非常規的編程方法,更為重要的是,在將數據與編程接口的其他部分合并時,它可能會引發某些問題。要一勞永逸地解決這一問題,您現在可以做一些重新編寫工作以期將來提供長期的 ADO.NET 收益。正如任何一般規則一樣,總是會有一些例外情況。在這種情況下,服務器游標是最顯著的一個。.NET 中的 ADO 代碼可能像石頭一樣堅硬,但從設計的角度看,維護和代碼過時也可能會使您的代碼僵化死板。

Developer’s Network Journal 2001 年 2 月刊中刊登了另一篇很好的 ADO.NET 文章。要閱讀這篇文章,請單擊以下鏈接: http://www.dnjonline.com/articles/essentials/iss22_essentials.html

對話欄:您是否(真的)準備好進行遷移?

Dino,您好!感謝您提供了非常精彩的 .NET 遷移文章。但是,如果我即將開始一個新項目,我不知道是否來得及使用 .NET。

要牢記的四點是:

?

我將向我在 Microsoft 的聯系人了解有關發行時間表的最新新聞。我并不在意像 Visual Studio .NET 之類的開發工具的可用性問題。我關心更多的是平臺二元性問題和好的文檔。在發行前三個月內進行準備就可以了,而不必在設計級別采取太多的預防措施。否則,我采取 50% 對 50% 的策略,因為您做兩手準備總不會有什么損失。實際上,我在在適當的時間進行遷移中介紹了如何進行規劃。

?

項目性質也是一個考慮事項。ASP.NET 與 Beta 2 很接近,我認為它在此時已非常可靠并且設計非常完善。我預計 API 不會發生很大的變化,而只是一些較小的更改和增加新的功能而已。當然,我預計在內存管理和總體性能方面還會有所提高。我認為 ADO.NET 也不會有什么變化。這包括簡單的讀取功能和更新。有關更復雜的需要,我只好等待 Beta 2 了。順便提一下,預計 Beta 2 是RTM 之前的最終測試階段。這應該給您提供了我做事情的思路:一半 ASP,一半 ASP.NET。

?

另一個考慮事項是最終期限 — 越循序漸進,效果越好。如果要我給上述問題做出一個二元性的解答(順便說一下,這根本無關緊要)的話,我要說的是:“我還沒有準備好使用 100% 純粹、真正的 .NET 系統。”我剛剛將我的 Intranet 作為 ASP.NET 應用程序進行了重新編寫,但與真實的系統相比,它看起來有點過于簡單了。但是,您不費力氣或方便地進行編碼就可獲取的功能達到的水平是非常令人吃驚的。如果將它與現實情況結合起來,那么,它具有的潛在優點無疑是會非常誘人和令人振奮的。我敢打賭,現在就遷移到 .NET 可贏得非常大的先機。我喜歡打賭,但我會確保了解盡可能多的游戲規則。

?

我的所有客戶都對 .NET 情有獨鐘。雖然只有一個客戶已采取實實在在的行動,但我們大家都在按照本文中所描述的原則穩步前行。總而言之,我認為從事研究工作并給您們提供正確的指導是一件令我非常開心的事情。這就是我現在正在做的事情,并且我建議您也這樣做。

Dino Esposito Wintellect 的 ADO.NET 專家兼培訓教員和顧問,工作地點位于意大利的羅馬。Dino 是 MSDN Magazine 的特約編輯,是 Cutting Edge 專欄的撰稿人。他還經常向 Developer Network Journal 和 MSDN News 投稿。Dino 是即將由 Microsoft Press 推出的《Building Web Solutions with ASP.NET and ADO.NET》一書的作者,也是 http://www.vb2themax.com/ 的創始人之一。如果希望與 Dino 聯系,可發送電子郵件至 dinoe@wintellect.com

轉入原英文頁面

ADO在.NET應用程序中揮灑自如


更多文章、技術交流、商務合作、聯系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!!!

發表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 成人国产在线视频 | 中文精品爱久久久国产 | 182午夜在线观看 | 久久夜靖品 | 日日欧美| 99色吧| 久久婷婷激情综合中文字幕 | 麻豆国产精品高中生视频 | 99色综合| 久久午夜伦理 | 亚洲精品区在线播放一区二区 | 国产香蕉免费精品视频 | 亚洲免费大片 | 99热久久这里就有精品 | 久久精视频 | 劲爆欧美色欧美 | 欧美破处在线 | 国产香蕉精品视频在 | 成人免费播放视频777777 | 激情五月婷婷基地 | 亚洲第一欧美 | 色姝影院免费 | 国产精品四虎视频一区 | 黄色高清在线观看 | a毛片久久免费观看 | 亚洲综合激情六月婷婷在线观看 | 亚洲香蕉网综合久久 | 国产精品国产高清国产专区 | 插久久| 久久婷婷成人综合色 | 欧美国产永久免费看片 | 亚洲视频精选 | 日韩一区二区超清视频 | 国产福利一区视频 | 88精品视频 | 色偷偷久久| 97视频久久久 | 欧美久久精品 | 精品一区 二区三区免费毛片 | 久久视频精品36线视频在线观看 | 免费国产精成人品 |