首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> 關於.NET

深入剖析 .NET PetShop 與 Duwamish:ADO.NET 資料庫程式設計模式的抉擇與實踐

     編輯:關於.NET

前言:ADO.NET 的多重選擇與開發者的困惑

ADO.NET 賦予開發者強大的資料庫操作能力,其內建的 DataReader、DataAdapter、DataSet 等物件提供了多樣化的程式設計路徑。然而,靈活性的背面往往伴隨著選擇的困擾:究竟該用 DataReader 還是 DataAdapter?僅需讀取少量資料,是否必須填滿整個 DataSet?為何 DataReader 不像經典 ADO 的 Recordset 那樣支援直接更新?DataSet 的核心優勢究竟在哪裡?

本文將透過對微軟兩大經典範例專案——.NET PetShop 與 Duwamish——的資料存取層實作進行深度剖析與對比,幫助您釐清觀念,依據實際業務需求制定最適合的資料庫程式設計模式。

兩大經典範例簡介

.NET PetShop:效能與簡潔的標竿

.NET PetShop 是微軟在著名的「寵物店大戰」中擊敗 J2EE PetStore 的獲勝之作,號稱以 27 倍效能優勢與 1/4 程式碼量完勝。儘管 Sun 曾質疑其公平性,但 PetShop 無疑是學習 .NET 高效能架構的經典教材。專案採用標準三層架構(表示層、中間層、資料層),程式碼精簡輕快,展現了 .NET 平台的極致效能潛力。

.NET PetShop 寵物網上商店首頁

Duwamish:企業級嚴謹度的典範

Duwamish 是一個外表簡單但內部極度複雜的線上書店完整應用範例。作為 Visual Studio .NET 官方 Enterprise Sample,它提供 C# 與 VB.NET 雙版本及大量中文文件。架構採用四層設計(表示層、業務外觀層、業務規則層、資料層),強調嚴謹的資料驗證、交易處理與系統健壯性,是企業級開發的教科書級參考。

Duwamish 網上電子書店首頁

架構脈絡:分層設計的異同

兩者皆採用 N 層架構,但分層粒度不同:

  • PetShop:三層架構(UI、BLL、DAL),中間層與資料層合置於 Components 目錄下的 .cs 檔案中。
  • Duwamish:四層架構(UI、Business Facade、Business Rules、DAL),各層獨立專案,職責劃分更細緻。

本文聚焦於資料存取模式,不展開架構優劣討論。

Duwamish 深度剖析:以 DataSet 為核心的離線模式

客製化 DataSet:型別安全的資料載體

Duwamish 採用 DataAdapter 填充 DataSet 的模式,並透過繼承 DataSet 建立強型別資料容器(如 BookData),在建構函式中預先定義資料表結構:

public class BookData : DataSet
{
    public BookData() { BuildDataTables(); }
    private void BuildDataTables()
    {
        DataTable table = new DataTable(BOOKS_TABLE);
        // 定義欄位:PKID, TYPE_ID, ISBN, TITLE, PRICE...
        this.Tables.Add(table);
    }
}

此設計將結構定義封裝於型別內,避免執行期的 Column Mapping 開銷,確保層間傳遞的型別安全與 IntelliSense 支援。

資料存取層實作:Stored Procedure + DataAdapter

資料層類別(如 Books)封裝 SqlDataAdapter,提供細粒度查詢方法:

private SqlDataAdapter dsCommand;
public BookData GetBookById(int bookId)
{
    return FillBookData("GetBookById", "@BookId", bookId.ToString());
}
private BookData FillBookData(string cmdText, string paramName, string paramValue)
{
    BookData data = new BookData();
    SqlCommand cmd = dsCommand.SelectCommand;
    cmd.CommandText = cmdText;
    cmd.CommandType = CommandType.StoredProcedure;
    cmd.Parameters.Add(new SqlParameter(paramName, paramValue));
    dsCommand.Fill(data);
    return data;
}

觀察可見,資料層直接暴露具體查詢方法(GetBookById),上層(業務規則層)則專注於嚴格的資料驗證與業務邏輯:

public CustomerData GetCustomerByEmail(string email, string password)
{
    // 前置條件驗證
    ApplicationAssert.CheckCondition(email != String.Empty, "Email address is required");
    ApplicationAssert.CheckCondition(password != String.Empty, "Password is required");
    
    // 呼叫資料層
    CustomerData dataSet;
    using (DataAccess.Customers da = new DataAccess.Customers())
        dataSet = da.LoadCustomerByEmail(email);
    
    // 密碼驗證邏輯
    DataRowCollection rows = dataSet.Tables[CustomerData.CUSTOMERS_TABLE].Rows;
    if (rows.Count == 1 && rows[0][CustomerData.PASSWORD_FIELD].Equals(password))
        return dataSet;
    return null;
}

這體現了企業級系統對健壯性的極致追求:資料層只管存取,驗證與邏輯上移至業務層。

.NET PetShop 深度剖析:DataReader 導向的線上輕量模式

資料層封裝:統一的 RunProc 回傳 DataReader

PetShop 資料層僅有一個 Database 類,核心方法 RunProc 直接回傳 SqlDataReader:

public void RunProc(string procName, out SqlDataReader dataReader)
{
    SqlCommand cmd = CreateCommand(procName, null);
    dataReader = cmd.ExecuteReader(CommandBehavior.CloseConnection);
}

此處 DataReader 扮演「資料指標」或「資料引用」角色,連線生命週期延長至讀取完成。

中間層手動分頁與物件映射

中間層(如 Product 類)接管 DataReader,手動實作分頁邏輯並映射至輕量 DTO 陣列:

public ProductResults[] GetList(string catId, int currentPage, int pageSize, ref int numResults)
{
    SqlDataReader reader = GetList(catId);
    ProductResults[] results = new ProductResults[pageSize];
    int start = (currentPage - 1) * pageSize;
    // 跳過前幾頁資料
    for (int i = 0; i < start - 1; i++) if (reader.Read()) numResults++;
    if (start > 1) reader.Read();
    // 讀取當頁資料
    while (reader.Read()) {
        if (index < pageSize) {
            results[index] = new ProductResults();
            results[index].productid = reader.GetString(0);
            results[index].name = reader.GetString(1);
            index++;
        }
        numResults++;
    }
    reader.Close();
    // 修剪陣列...
    return results;
}

DTO 定義極簡:

public class ProductResults
{
    public string productid { get; set; }
    public string name { get; set; }
}

此模式避免了 DataSet 序列化開銷,僅傳輸必要欄位,並將分頁邏輯下推至中間層,大幅減少記憶體佔用與網路傳輸量。

模式對比總結與選型指南

維度Duwamish (DataSet/離線)PetShop (DataReader/線上)
核心物件DataSet (強型別衍生類)DataReader + 自訂 DTO
連線模式離線:Fill 即關閉連線線上:讀取期間保持連線
資料更新DataAdapter.Update() 批次離線更新Command.ExecuteNonQuery() 即時線上更新
架構風格嚴謹、龐大、企業級健壯輕量、敏捷、效能導向
適用場景複雜業務邏輯、大量批次更新、高併發需快速釋放連線以讀為主、需高效能分頁、簡單 CRUD、資料量大但顯示少

關鍵取捨建議

  • 唯讀、高頻、大量資料分頁顯示 → 首選 DataReader + 手動映射 (PetShop 模式),減少記憶體壓力,縮短連線佔用(配合 CommandBehavior.CloseConnection)。
  • 複雜更新、批次操作、需資料關係/約束驗證、離線編輯 → 首選 DataSet + DataAdapter (Duwamish 模式),利用離線特性批次提交,降低資料庫鎖定時間。
  • 連線管理:PetShop 將連線保持至中間層讀取完畢,雖簡化程式碼,但高併發下可能耗盡連線池;Duwamish 填充即釋放,更利於擴展性。
  • 實際專案多為混合:查詢用 DataReader/DTO,複雜表單編輯用 DataSet,關鍵在於依業務特性在恰當層級選擇恰當工具。

結語

.NET PetShop 與 Duwamish 代表了微軟內部不同團隊對 ADO.NET 最佳實踐的兩種詮釋:一極致效能與簡潔,一極致規範與健壯。沒有銀彈,只有權衡。理解兩種模式的核心機制——線上流式讀取 vs 離線快照操作、手動映射 vs 自動填充、即時命令 vs 批次更新——才能在真實專案中遊刃有餘。

若您對此議題有更深入探討意願,歡迎來信交流:nluyan@163.NET

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved