熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> .NET編程 >> 正文

數據層組件設計與數據傳遞二

2013-11-13 10:04:23  來源: .NET編程 

  實現業務實體

  業務實體具有以下特點
業務實體提供對業務數據及相關功能(在某些設計中)的狀態編程訪問
業務實體可以使用具有復雜架構的數據來構建這種數據通常來自數據庫中的多個相關表
業務實體數據可以作為業務過程的部分 I/O 參數傳遞
業務實體可以是可序列化的以保持它們的當前狀態例如應用程序可能需要在本地磁盤桌面數據庫(如果應用程序脫機工作)或消息隊列消息中存儲實體數據
業務實體不直接訪問數據庫全部數據庫訪問都是由相關聯的數據訪問邏輯組件提供的
業務實體不啟動任何類型的事務處理事務處理由使用業務實體的應用程序或業務過程來啟動

  如本文前面所述在您的應用程序中表示業務實體的方法有很多(從以數據為中心的模型到更加面向對象的表示法)
XML
通用 DataSet
有類型的 DataSet
自定義業務實體組件
帶有 CRUD 行為的自定義業務實體組件

  以下各節將介紹如何使用這些格式來表示業務實體為幫助您確定特定環境中最適宜的業務實體表示以下各節將介紹如何為各業務實體格式執行以下任務
組織業務實體集合
將業務實體數據綁定到用戶界面控件
序列化業務實體數據
在層間傳遞業務實體數據

  以下各節還針對非功能性要求(包括性能效率可縮放性和可擴展性)考慮了每種業務實體表示的適用性

將業務實體表示為 XML

  以下示例顯示了如何將一個簡單的業務實體表示為 XML該業務實體包含一個產品

<?xml version=?>
<Product xmlns=urn:aUniqueNamespace
<ProductID></ProductID>
<ProductName>Chai</ProductName>
<QuantityPerUnit> boxes x bags</QuantityPerUnit>
<UnitPrice></UnitPrice>
<UnitsInStock></UnitsInStock>
<UnitsOnOrder></UnitsOnOrder>
<ReorderLevel></ReorderLevel>
</Product>

  當使用 XML 表示業務實體數據時請考慮以下原則


確定 XML 文檔是包含單個業務實體還是包含一個業務實體集合前面的示例表示的是單個 Product 業務實體
使用一個命名空間唯一標識該 XML 文檔以避免與其他 XML 文檔的內容發生命名沖突前面的示例使用名為 urn:aUniqueNamespace 的默認命名空間
為元素和屬性選擇合適的名稱前面的示例使用 Product 表的列名稱但並不要求一定這樣可以選擇對您的應用程序有意義的名稱
使用以下方法之一以 XML 格式檢索您的業務實體
如果您使用的是 SQL Server 則可以在查詢或存儲過程中使用 FOR XML 子句在性能測試中使用 FOR XML 只比返回 DataSet 稍微快一點
檢索 DataSet 並將其轉換為 XML 流或以 XML 流的格式寫出這種方法會帶來創建 DataSet 的系統開銷和額外的轉換開銷(如果執行轉換)
使用輸出參數或數據讀取器構建一個 XML 文檔數據讀取器是從數據庫檢索多個行的最快方法但與構建 XML 相關聯的過程可能會減弱這種性能優勢

  將業務實體表示為 XML 的優點如下


標准支持XML 是 World Wide Web Consortium (WC) 的標准數據表示格式
靈活性XML 能夠表示信息的層次結構和集合
互操作性在所有平台上XML 都是與外部各方及貿易伙伴交換信息的理想選擇如果 XML 數據將由 應用程序或 Windows 窗體應用程序使用則還可以把這些 XML 數據裝載到一個 DataSet 中以利用 DataSet 提供的數據綁定支持

  將業務實體表示為 XML 的缺點如下
類型保真XML 不支持類型保真然而對於簡單的數據分類可以使用 XSD 架構
驗證 XML要驗證 XML可以手動分析代碼或者使用 XSD 架構但這兩種方法都比較慢
顯示 XML您不能將 XML 數據自動顯示在用戶界面上可以編寫一個 XSLT 樣式表將數據轉換為 DataSet但樣式表的編寫比較麻煩另一種方法是通過樣式表將 XML 轉換為 HTML 等可顯示格式
分析 XML要分析 XML可以使用文檔對象模型 (DOM) 或 Microsoft NET Framework 類庫提供的 XmlReader 類XmlReader 提供對 XML 數據的快速只讀的僅向前的訪問而 DOM 可以提供隨機讀/寫訪問因此更靈活然而使用 DOM 分析 XML 文檔的速度較慢您必須創建一個 XmlDocument 實例(或另一個 XML 分析器類)並把整個 XML 文件裝載到內存中
排序 XML您不能自動排序 XML 數據而應使用以下技術之一
按預先排好的順序提供數據這種方法不支持在調用應用程序中動態重新排序數據
應用 XSLT 樣式表動態排序數據如果需要可以使用 DOM 在運行時改變 XSLT 樣式表中的排序條件
將 XML 數據轉換為 DataSet並使用 DataView 對象排序和搜索數據元素
使用專用字段您不能選擇隱藏信息   將業務實體表示為通用 DataSet

  通用 DataSet 是 DataSet 類的實例它是在 ADONET 的 SystemData 命名空間中定義的DataSet 對象包含一個或多個 DataTable 對象用以表示數據訪問邏輯組件從數據庫檢索到的信息

  圖 所示為用於 Product 業務實體的通用 DataSet 對象該 DataSet 對象具有一個 DataTable用於保存產品信息該 DataTable 具有一個 UniqueConstraint 對象用於將 ProductID 列標記為主鍵DataTable 和 UniqueConstraint 對象是在數據訪問邏輯組件中創建該 DataSet 時創建的

  

  用於 Product 業務實體的通用 DataSet

  圖 所示為用於 Order 業務實體的通用 DataSet 對象此 DataSet 對象具有兩個 DataTable 對象分別保存訂單信息和訂單詳細信息每個 DataTable 具有一個對應的 UniqueConstraint 對象用於標識表中的主鍵此外該 DataSet 還有一個 Relation 對象用於將訂單詳細信息與訂單相關聯

  

  用於 Order 業務實體的通用 DataSet

  以下代碼顯示了如何從數據訪問邏輯組件檢索通用 DataSet 然後將該 DataSet 綁定到 DataGrid 控件再將該 DataSet 傳遞到數據訪問邏輯組件以保存對數據所做的更改

// 創建 ProductDALC 對象
ProductDALC dalcProduct = new ProductDALC();

  // 對 ProductDALC 調用一個方法以獲取一個包含全部產品信息的 DataSet
DataSet dsProducts = dalcProductGetProducts();

  // 在客戶端中使用 DataSet 例如把該 DataSet 綁定到用戶界面控件
dataGridDataSource = dsProductsTables[]DefaultView;
dataGridDataBind();

  // 然後把更新後的 DataSet 傳遞給 ProductDALC將更改
// 保存到數據庫
dalcProductUpdateProducts(dsProducts);

  您還可以在運行時查詢和修改 DataSet 中的表約束及關系

  將業務實體表示為通用 DataSet 的優點如下
靈活性DataSet 可以包含數據的集合能夠表示復雜的數據關系
序列化在層間傳遞時DataSet 本身支持序列化
數據綁定可以把 DataSet 綁定到 ASPNET 應用程序和 Windows 窗體應用程序的任意用戶界面控件
排序與過濾可以使用 DataView 對象排序和過濾 DataSet應用程序可以為同一個 DataSet 創建多個 DataView 對象以便用不同方式查看數據
與 XML 的互換性可以用 XML 格式讀寫 DataSet這種方法在遠程和脫機應用程序中很有用它可以用 XML 格式接收 DataSet然後在本地重新創建該 DataSet 對象應用程序在與數據庫斷開連接後還可以將 DataSet 保持為 XML 格式
元數據的可用性可以用 XSD 架構的形式為 DataSet 提供完整的元數據還可以使用 DataSetDataTableDataColumnConstraint 和 Relation 類中的方法以編程方式為 DataSet 獲取元數據
開放式並發在更新數據時可以配合使用數據適配器與 DataSet 以方便地執行開放式並發檢查
可擴展性如果修改了數據庫架構則適當情況下數據訪問邏輯組件中的方法可以創建包含修改後的 DataTable 和 DataRelation 對象的 DataSet數據訪問邏輯組件方法簽名並不改變可以將調用應用程序修改為使用該 DataSet 中的這些新元素

  將業務實體表示為通用 DataSet 的缺點如下
客戶端代碼必須通過 DataSet 中的集合訪問數據要訪問 DataSet 中的表客戶端代碼必須使用整數索引生成器或字符串索引生成器來索引 DataTable 集合要訪問特定列必須使用列編號或列名稱索引 DataColumn 集合以下示例顯示了如何訪問 Products 表中第一行的 ProductName 列

// 獲取所調用的名為 dsProducts 的 DataSet 的第一行的
// 產品名稱 注意該集合是基於零的
String str = (String)dsProductsTables[Products]Rows[][ProductName];


注意這裡沒有這些索引生成器的編譯時檢查如果指定一個無效的表名稱列名稱或列類型會在運行時捕獲該錯誤使用通用 DataSet 時不支持 IntelliSense

實例化和封送處理的成本很高DataSet 需要創建多個子對象(DataTableDataRow 和 DataColumn)這意味著在實例化和封送處理時DataSet 會比 XML 字符串或自定義實體組件花費更長的時間隨著數據量的增大創建 DataSet 內部結構的系統開銷將明顯少於將數據填充到 DataSet 中所需的開銷因此 DataSet 的相對性能會隨之提高
專用字段您不能選擇隱藏信息   將業務實體表示為有類型的 DataSet

  有類型的 DataSet 是包含具有嚴格類型的方法屬性和類型定義以公開 DataSet 中的數據和元數據的類

  下面列出了有類型的 DataSet 與通用 DataSet 相比的優缺點注意有類型的 DataSet 的實例化和封送處理性能與通用 DataSet 基本相同

  將業務實體表示為有類型的 DataSet 的優點如下
代碼易讀要訪問有類型的 DataSet 中的表和列可以使用有類型的方法和屬性如以下代碼所示


// 獲取所調用的名為 dsProducts 的有類型的 DataSet 的第一行的
// 產品名稱注意該集合是基於零的
String str = dsProductsProducts[]ProductName;


  在本示例中dsProducts 是有類型的 DataSet 的一個實例該 DataSet 有一個 DataTable它由一個命名為 Products 的屬性公開該 DataTable 中的列由 ProductName 等屬性公開後者返回列的相應數據類型(而不僅僅返回對象)

  有類型的方法和屬性的提供使得使用有類型的 DataSet 比使用通用 DataSet 更方便使用有類型的 DataSet 時IntelliSense 將可用


編譯時類型檢查無效的表名稱和列名稱將在編譯時而不是在運行時檢測

  將業務實體表示為有類型的 DataSet 的缺點如下
部署必須將包含有類型的 DataSet 類的程序集部署到使用業務實體的所有層
支持企業服務 (COM+) 調用程序如果有類型的 DataSet 將由 COM+ 客戶端使用則必須為包含該有類型的 DataSet 類的程序集提供一個嚴格名稱並且必須在客戶端計算機上注冊通常該程序集安裝在全局程序集緩存中這些也是自定義實體類所要求的步驟如本文後面所述
可擴展性問題如果修改了數據庫架構則可能需要重新生成有類型的 DataSet 類以支持新架構重新生成過程將不會保留在有類型的 DataSet 類中實現的任何自定義代碼必須將包含有類型的 DataSet 類的程序集重新部署到所有客戶端應用程序中
實例化您不能使用 new 運算符來實例化類型
繼承有類型的 DataSet 必須從 DataSet 類繼承這會禁止使用任何其他基本類

  定義自定義業務實體組件

  表示業務實體的自定義類通常包含以下成員
用於在本地緩存業務實體的數據的專用字段這些字段在數據訪問邏輯組件從數據庫檢索數據時保存數據庫數據的一個快照
用於訪問實體的狀態和訪問實體內數據的子集及層次結構的公共屬性這些屬性的名稱可以與數據庫的列名稱相同但這並不是一個絕對要求可以根據您的應用程序的需要選擇屬性名而不必使用數據庫中的名稱
用以使用實體組件中的數據執行本地化處理的方法和屬性
用以通知實體組件內部狀態變化的事件

  圖 所示為使用自定義實體類的方法注意實體類並不知道數據訪問邏輯組件或基礎數據庫所有數據庫訪問都由數據訪問邏輯組件執行以集中數據訪問策略和業務邏輯此外在層間傳遞業務實體數據的方式與表示業務實體的格式也沒有直接關系例如可以在本地將業務實體表示為對象而用另一種方法(如標量值或 XML)將業務實體數據傳遞到其他層

  

  


自定義業務實體組件的作用

    定義自定義業務實體組件的建議

  在實現自定義實體組件時請考慮以下建議
選擇使用結構還是使用類對於不包含分層數據或集合的簡單業務實體可以考慮定義一個結構來表示業務實體對於復雜的業務實體或要求繼承的業務實體可將實體定義為類
表示業務實體的狀態對於數字字符串等簡單值可以使用等價的 數據類型來定義字段
表示自定義業務實體組件中的子集合和層次結構表示自定義實體中的數據的子集合和層次結構的方法有兩種
NET 集合(例如 ArrayList)NET 集合類為大小可調的集合提供了一個方便的編程模型還為將數據綁定到用戶界面控件提供了內置的支持
DataSetDataSet 適合於存儲來自關系數據庫或 XML 文件的數據的集合和層次結構此外如果需要過濾排序或綁定子集合也應首選 DataSet

支持用戶界面客戶端的數據綁定如果自定義實體將要由用戶界面使用並且希望利用自動數據綁定可能需要在自定義實體中實現數據綁定請考慮以下方案
Windows 窗體中的數據綁定您可以將實體實例的數據綁定到控件而不必在自定義實體中實現數據綁定接口也可以綁定實體的數組或 NET 集合
Web 窗體中的數據綁定如果不實現 IBindingList 接口則不能將實體實例的數據綁定到 Web 窗體中的控件然而如果只想綁定集合則可以使用數組或 NET 集合而不必在自定義實體中實現 IBindingList 接口
公開內部數據更改的事件公開事件可以獲得豐富的客戶端用戶界面設計因為它使得無論數據顯示在哪裡都可以對其進行刷新事件應當只針對內部狀態而不是針對服務器上的數據更改
使業務實體可序列化使業務實體可序列化可以將業務實體的狀態保持在中間狀態而不進行數據庫交互這樣可以方便脫機應用程序的開發和復雜用戶界面過程的設計即在完成前不會影響業務數據序列化有兩種類型
使用 XmlSerializer 類進行 XML 序列化如果只需要把公共字段和公共讀/寫屬性序列化為 XML則可以使用 XML 序列化注意如果從 Web 服務返回業務實體數據對象將通過 XML 序列化自動序列化為 XML

  您可以對業務實體執行 XML 序列化而無需在實體中實現任何附加代碼然而只有對象中的公共字段和公共讀/寫屬性被序列化為 XML專用字段索引生成器專用屬性只讀屬性及對象圖不會被序列化您可以使用自定義實體中的屬性控制結果 XML


使用 BinaryFormatter 或 SoapFormatter 類進行格式序列化如果需要序列化對象的所有公共字段專用字段及對象圖或者需要與遠程服務器之間傳遞實體組件則可以使用格式序列化

  格式類將序列化對象的所有公共和專用字段及屬性BinaryFormatter 將對象序列化為二進制格式SoapFormatter 將對象序列化為 SOAP 格式使用 BinaryFormatter 的序列化比使用 SoapFormatter 的序列化速度要快要使用任何一個格式類都必須將實體類標記為 [Serializable] 屬性如果需要顯式控制序列化格式您的類還必須實現 ISerializable 接口

注意還原序列化某個對象時不會調用默認的構造函數對還原序列化添加這項約束是出於性能方面的考慮

  定義自定義實體的優點如下
代碼易讀要訪問自定義實體類中的數據可以使用有類型的方法和屬性如以下代碼所示 // 創建一個 ProductDALC 對象
ProductDALC dalcProduct = new ProductDALC();

  // 使用該 ProductDALC 對象創建和填充一個 ProductEntity 對象
// 此代碼假設 ProductDALC 類有一個名為 GetProduct 的方法
// 該方法使用 Product ID 作參數(本例中為 並返回一個
// 包含該產品的所有數據的 ProductEntity 對象
ProductEntity aProduct = dalcProductGetProduct();

  // 更改該產品的產品名稱
aProductProductName = Roasted Coffee Beans;

  在上述示例中產品是一個名為 ProductEntity 的自定義實體類的一個實例ProductDALC 類有一個名為 GetProduct 的方法後者創建一個 ProductEntity 對象將某個特定產品的數據填充到該對象然後返回 ProductEntity 對象調用應用程序可以使用 ProductName 等屬性訪問 ProductEntity 對象中的數據並且可以調用方法以操作該對象


封裝自定義實體可以包含方法以封裝簡單的業務規則這些方法操作緩存在實體組件中的業務實體數據而不是訪問數據庫中的實時數據請考慮以下示例 // 調用一個在 ProductEntity 類中定義的方法
aProductIncreaseUnitPriceBy();

  在上述示例中調用應用程序對 ProductEntity 對象調用一個名為 IncreaseUnitPriceBy 的方法在調用應用程序對 ProductDALC 對象調用相應方法從而將 ProductEntity 對象保存到數據庫之前這一更改並不是永久性的


構建復雜系統的模型在構建復雜域問題(在不同業務實體之間存在很多交互)的模型時可以定義自定義實體類從而將復雜性隱藏在經過很好定義的類接口的後面
本地化驗證自定義實體類可以在其屬性存取器中執行簡單的驗證測試以檢測無效的業務實體數據
專用字段您可以隱藏不希望向調用程序公開的信息

  定義自定義實體的缺點如下
業務實體集合自定義實體表示的是單個業務實體而不是一個業務實體集合要保存多個業務實體調用應用程序必須創建一個數組或一個 NET 集合
序列化您必須在自定義實體中實現自己的序列化機制可以使用屬性來控制實體組件的序列化方式也可以通過實現 ISerializable 接口來控制自己的序列化
表示業務實體中的復雜關系和層次結構您必須在業務實體組件中實現自己的關系和層次結構表示機制如前面所述DataSet 通常是實現這一目的的最簡單方式
搜索和排序數據您必須定義自己的機制來支持實體的搜索和排序例如可以通過實現 IComparable 接口以便將實體組件保存在一個 SortedList 集合或 Hashtable 集合中
部署您必須在所有物理層部署包含自定義實體的程序集
支持企業服務 (COM+) 客戶端如果一個自定義實體將由 COM+ 客戶端使用則必須為包含該實體的程序集提供一個嚴格名稱並且必須在客戶端計算機上注冊通常該程序集安裝在全局程序集緩存中
可擴展性問題如果修改了數據庫架構則可能需要修改自定義實體類並重新部署程序集

    定義帶有 CRUD 行為的自定義業務實體組件

  在定義一個自定義實體時可以提供方法以完全封裝對基礎數據訪問邏輯組件的 CRUD 操作這是比較傳統的面向對象的方法可能適用於復雜的對象域客戶端應用程序不再直接訪問數據訪問邏輯組件類而是創建一個實體組件並對該實體組件調用 CRUD 方法這些方法將調用基礎的數據訪問邏輯組件

  圖 所示為帶有 CRUD 行為的自定義實體類的作用

  

  


帶有 CRUD 行為的自定義業務實體組件的作用

  定義帶有 CRUD 行為的自定義實體類的優點如下
封裝自定義實體可以封裝由基礎數據訪問邏輯組件定義的操作
與調用程序的接口調用程序必須只處理一個接口來保持業務實體數據不必直接訪問數據訪問邏輯組件
專用字段您可以隱藏不希望向調用程序公開的信息

  定義帶有 CRUD 行為的自定義實體類的缺點如下
處理業務實體集合自定義實體中的方法屬於單個業務實體實例要支持業務實體集合可以定義靜態方法以讀取或返回一個數組或一個實體組件集合
開發時間長傳統的面向對象方法通常比使用現有對象(如 DataSet)需要更多的設計和開發工作

    表示數據和在層間傳遞數據的建議

  在您的應用程序中表示數據的方式以及在層間傳遞數據的方式不一定要相同然而一套一致而有限的格式能夠降低對附加轉換層的需要從而提高性能並方便維護

  應根據自己特定的應用程序要求和操作數據的方式選擇數據格式這裡並沒有一個通用的表示方式特別是由於當今的許多應用程序都需要支持多個調用程序然而我們還是建議遵循以下一般原則
如果您的應用程序主要處理集合並需要排序搜索和數據綁定等功能則建議采用 DataSet但如果應用程序處理實例數據則采用標量值的效果會更好
如果您的應用程序主要處理實例數據則自定義業務實體組件可能是最佳選擇因為它們可以消除一個 DataSet 表示一行時的系統開銷
大多數情況下應把應用程序設計為使用 XML 文檔DataSet 等以數據為中心的格式可以利用 DataSet 提供的靈活性及固有功能來更方便地支持多個客戶端減少自定義代碼的數量並使用為大多數開發人員所熟知的編程 API雖然以面向對象的方式操作數據有很多好處但自定義編碼復雜的業務實體會使開發和維護成本隨所提供功能的數量成比例增加

  事務處理

  當今的大多數應用程序都需要支持事務處理以保持系統數據的完整性事務處理的管理方法有多種但每種方法都可歸於以下兩種基本編程模型之一
手動事務處理直接在組件代碼或存儲過程中編寫使用 ADONET 或 TransactSQL 事務處理支持功能的代碼
自動事務處理使用企業服務 (COM+) 為 NET 類添加聲明屬性以便在運行時指定對象的事務性要求使用這種模型可以方便地配置多個組件以執行同一事務中的工作

  本節提供一些指導原則和建議幫助您在數據訪問邏輯組件和業務實體組件中實現事務處理支持

實現事務處理

  在大多數環境中事務處理的根本是業務過程而不是數據訪問邏輯組件或業務實體組件這是因為業務過程一般要求事務處理跨多個業務實體而不僅僅是單個業務實體

  然而也可能出現在沒有高層次業務過程的幫助下對單個業務實體執行事務性操作的情況例如要把一個新客戶添加到前面討論的數據庫中您必須執行以下操作
在 Customer 表中插入新的一行
在 Address 表中插入新的一行或多行

  只有這兩個操作都成功後客戶才會被添加到數據庫中如果 Customer 業務實體不會成為啟動該事務處理的更大的業務過程的一部分則應在 Customer 業務實體中使用手動事務處理手動事務處理不要求與 Microsoft 分布式事務處理協調器 (DTC) 之間進行任何進程間通信因此比自動事務處理要快得多

  圖 所示為確定使用手動事務處理還是自動事務處理的方法由於 COM+ 事務處理的系統開銷建議將事務處理放到數據庫中並在存儲過程中控制事務性行為(如果可能)

  

  確定如何實現事務處理

注意如果從基於 的客戶端進行調用並且沒有用於啟動事務處理的業務過程則您可能會從 ASPNET 代碼中啟動該事務處理這種設計並不好您決不能從基於 ASPNET 的客戶端啟動事務處理而應將數據的展示與業務過程相分離此外由於網絡滯後等問題還會導致性能問題因為這是要實際部署在其他層上的最常見的層

    在數據訪問邏輯組件中使用手動事務處理的建議

  在數據訪問邏輯組件中實現手動事務處理時請考慮以下建議
盡可能在存儲過程中執行處理使用 TransactSQL 語句 BEGIN TRANSACTIONEND TRANSACTION 和 ROLLBACK TRANSACTION 控制事務處理
如果沒有使用存儲過程並且也不會從業務過程中調用數據訪問邏輯組件則可以使用 ADONET 來編程控制事務處理

    在數據訪問邏輯組件中使用自動事務處理的建議

  雖然 COM+ 事務處理會帶來一些系統開銷但自動事務處理能夠提供比手動事務處理更簡單的編程模式而且在事務處理跨多個分布式數據源(與 DTC 一起工作)時必須使用自動事務處理在數據訪問邏輯組件中實現自動事務處理時請考慮以下建議
數據訪問邏輯組件必須是從 SystemEntERPriseServices 命名空間中的 ServicedComponent 類繼承而來注意使用 COM+ 服務注冊的所有程序集都必須具有嚴格的名稱
使用 Transaction(TransactionOptionSupported) 屬性注釋數據訪問邏輯組件以便可以在同一組件中執行讀寫操作與 Transaction(TransactionOptionRequired) 不同此選項在不需要事務處理時避免了不必要的系統開銷而前者始終會要求事務處理

  以下代碼示例顯示了如何在數據訪問邏輯組件類中支持自動事務處理

   using SystemEnterpriseServices;

  [Transaction(TransactionOptionSupported)]
public class CustomerDALC : ServicedComponent
{

}

  如果使用自動事務處理則數據訪問邏輯組件應在事務處理中表明操作是否成功如果要隱式表明應使用 AutoComplete 屬性注釋您的方法並在操作失敗時發出一個異常如果要顯式表明應對 ContextUtil 類調用 SetComplete 或 SetAbort 方法

    在業務實體組件中使用自動事務處理

  在實現帶有行為的自定義業務實體組件時可以使用自動事務處理來指定這些對象的事務性行為有關使用自動事務處理指定業務實體組件事務性行為的建議與前述有關在數據訪問邏輯組件中實現自動事務處理的建議相同

注意如果業務實體組件不包含任何要求其在事務處理中表明是否成功的業務邏輯則它可以忽略事務處理環境自定義業務實體組件不需要從 ServicedComponent 繼承事務處理環境仍將繼續其流程但實體組件將忽略事務處理環境

    驗證

  您可以在應用程序的許多層上進行數據驗證各層適用不同的驗證類型
在提交數據之前客戶端應用程序可以在本地驗證業務實體數據
使用 XSD 架構接收業務文檔時業務過程可以驗證這些文檔
數據訪問邏輯組件和存儲過程可以驗證數據以確保引用的完整性並強制遵循約束以及重要的業務規則

  常用驗證有兩種
即時點驗證這是在一個特定時點執行的驗證例如在接收 XML 文檔時由業務過程對其進行驗證
連續驗證這是在應用程序的許多不同層次上持續進行的一種驗證連續驗證的示例包括
用戶界面可以指定字段的最大長度以防止用戶輸入過長的字符串
DataSet 可以指定數據列的最大長度
自定義業務實體組件可以對實體數據執行范圍檢查長度檢查非空檢查以及其他簡單測試
數據訪問邏輯組件存儲過程和數據庫本身可以執行類似的測試以便在將數據保存到數據庫之前確保其有效性

  有時您可能希望實現額外的聚合過程或轉換過程這種方法在驗證和轉換經常變化時可能很有用但會損失性能例如如果一個 ISV 想要使用相同的組件支持數據庫架構的兩個版本則您可以創建一個單獨的組件來執行兩個數據庫架構版本之間的驗證和轉換

  如何使用 XSD 架構驗證 XML

  要使用 XSD 架構驗證 XML 文檔請執行以下步驟


    創建一個 XmlValidatingReader 對象作為 XmlTextReader 對象的包裝如以下代碼所示

    創建 XmlValidatingReader 對象以讀取和驗證 Productxml
    XmlTextReader tr = new XmlTextReader(Productxml);
    XmlValidatingReader vr = new XmlValidatingReader(tr);

    通過使用 ValidationType 枚舉指定所需的驗證類型NET Framework 支持三種類型的 XML 驗證
    文檔類型定義 (DTD)指定 ValidationTypeDTD
    Microsoft XML 精簡數據 (XDR) 架構指定 ValidationTypeXDR
    WC 標准 XSD 架構指定 ValidationTypeSchema

      以下代碼顯示了 ValidationType 枚舉的使用

    vrValidationType = ValidationTypeSchema; 指定 XSD 架構驗證


    注冊一個驗證事件處理程序方法如以下代碼所示

    vrValidationEventHandler += new ValidationEventHandler(MyHandlerMethod);

    提供一個驗證事件處理程序方法的實現如以下代碼所示

    public void MyHandlerMethod(object sender ValidationEventArgs e)
    {
    ConsoleWriteLine(驗證錯誤: + eMessage);
    }
    讀取和驗證文檔如以下代碼所示驗證錯誤將被驗證事件處理程序方法拾取

    try
    {
    while (vrRead())
    {
    // 適當處理 XML 數據
    }
    }
    catch (XmlException ex)
    {
    ConsoleWriteLine(XmlException: + exMessage);
    }
    vrClose();

    如何在業務實體組件的屬性存取器中驗證數據

  以下代碼片段顯示了如何在自定義實體的屬性存取器中進行簡單驗證如果驗證測試失敗您可以發出一個異常以顯示問題的性質也可以在屬性存取器集合中使用正則表達式來驗證特定的數據和格式

   public class ProductDALC
{

public short ReorderLevel
{
get { return reorderLevel; }
}
set
{
if (value <
{
throw new ArgumentOutOfRangeException(ReorderLevel 不能為負數);
}
reorderLevel = value;
}

  // 加上 ProductDALC 類中的其他成員
}

  異常管理

  當 應用程序出現錯誤時通常的建議是發出異常而不是從方法返回錯誤值這一建議暗示了您編寫數據訪問邏輯組件和業務實體組件的方式異常大體上有兩種
技術異常它包括
ADONET
數據庫連接
資源(如數據庫網絡共享消息隊列等)不可用
業務邏輯異常它包括
驗證錯誤
實現業務邏輯的存儲過程中的錯誤   在數據訪問邏輯組件中管理異常的建議

  數據訪問邏輯組件應該傳播異常並且僅在能夠使客戶端對異常的管理更加容易時才包裝異常類型將異常包裝為兩種主要異常類型(技術異常和業務異常)有利於各種可能的調用程序的異常處理結構和異常發布邏輯

  您的應用程序應當發布異常信息可以將技術異常發布到一個由系統管理員或 Windows 管理規范 (WMI) 監視工具(如 Microsoft Operations Manager)監視的日志中將業務異常發布到一個特定的應用程序日志中通常應允許從數據訪問邏輯組件傳播異常並允許由調用程序發布異常以便您了解異常的整個環境

  以下示例說明了這些建議

public class CustomerDALC
{
public void UpdateCustomer(Dataset aCustomer)
{
try
{
// 更新數據庫中的客戶
}
catch (SqlException se)
{
// 捕獲並包裝異常然後重新發出
throw new DataAccessException(數據庫不可用 se);
}
finally
{
// 清除代碼
}
}
}

  在業務實體組件中管理異常的建議

  業務實體組件應當向調用程序傳播異常在業務實體組件執行驗證或者當調用程序試圖執行某一操作而未提供該操作所需的數據時業務實體組件也可以產生異常

  以下示例顯示了業務實體組件如何產生異常在此示例中如果沒有提供客戶的名字Update 方法將發出一個異常

public class CustomerEntity
{
public void Update()
{
// 檢查用戶已提供了所需數據這裡是客戶
// 的名字
if (FirstName == )
{
// 發出一個已定義的新的應用程序異常
throw new MyArgumentException(您必須提供名字);
}

}
}

  授權與安全性

  本節說明如何將安全性應用於數據訪問邏輯組件和業務實體組件NET 公共語言運行庫使用權限對象實現其對托管代碼的強制限制機制權限對象有三種各自具有特定的用途
代碼訪問安全性這些權限對象用於防止未經授權使用資源和操作
身份標識這些權限對象指定運行程序集時所必需的身份標識特征
基於角色的安全性這些權限對象提供了一個機制用於判斷用戶(或用戶的代理人)是否具有特定身份標識或者是否是指定角色的成員PrincipalPermission 對象是唯一基於角色的安全性權限對象

  托管代碼可以使用 Principal 對象(包含對 Identity 對象的引用)來判斷當事人的身份標識或角色把 Identity 對象和 Principal 對象與用戶組帳戶等大家所熟悉的概念比較可能會更容易理解NET Framework 中Identity 對象表示用戶而角色表示成員身份和安全性環境Principal 對象封裝了 Identity 對象和角色NET Framework 中的應用程序根據 Principal 對象的身份標識或角色成員身份(後者更常見)授予 Principal 對象權限

  數據訪問邏輯組件中的安全性建議

  數據訪問邏輯組件的設計目的是供其他應用程序組件使用它也是您的應用程序代碼中在調用程序可以訪問數據之前實現安全性的最後一個地方

  通常數據訪問邏輯組件可以依賴於由調用程序設置的安全性環境然而有些情況下數據訪問邏輯組件必須執行自己的授權檢查以確定是否允許當事人執行所請求的操作授權在身份驗證後進行並使用當事人身份標識與角色等有關信息來確定該當事人可以訪問的資源

  在以下情況下應在數據訪問邏輯組件層次上執行授權檢查
需要與不完全信任的業務過程開發人員共享數據訪問邏輯組件
需要保護對數據存儲提供的強大功能的訪問

  在定義了 Identity 對象和 Principal 對象後可以用三種方式執行基於角色的安全性檢查
使用 PrincipalPermission 對象執行強制性安全性檢查
使用 PrincipalPermissionAttribute 屬性執行說明性安全性檢查
使用 Principal 對象中的屬性和 IsInRole 方法執行顯式安全性檢查

  以下代碼示例顯示了如何使用 PrincipalPermissionAttribute 為數據訪問邏輯組件類中的方法指定基於角色的聲明性安全性檢查

using System;
using SystemSecurityPermissions;

  public class CustomerDALC
{

  public CustomerDALC()
{
}

  // 使用 PrincipalPermissionAttribute 要求此方法的調用程序
// 具有一個名為MyUser的身份標識並且屬於角色Administrator
[PrincipalPermissionAttribute(SecurityActionDemand
Name=MyUser Role=Administrator)]
public void DeleteCustomer(string customerID)
{
// 在此處刪除客戶代碼
}
}

  以下代碼顯示了如何創建具有所需身份標識和角色的 Principal 對象以便對 CustomerDALC 對象調用 DeleteCustomer 方法

  using System;
using SystemSecurityPrincipal;
using SystemThreading;

  public class MainClass
{
public static int Main(string[] args)
{
ConsoleWrite(用戶名:);
string UserName = ConsoleReadLine();

  ConsoleWrite(密碼:);
string Password = ConsoleReadLine();

  if (Password == password && UserName == MyUser)
{
// 創建一個名為MyUser的通用身份標識
GenericIdentity MyIdentity = new GenericIdentity(MyUser);

  // 創建角色
String[] MyString = {Administrator User};

  // 創建一個通用當事人
GenericPrincipal MyPrincipal = new GenericPrincipal(MyIdentity
MyString);

// 設置此線程的當前當事人以用於基於角色的安全性
ThreadCurrentPrincipal = MyPrincipal;
}

  // 創建一個 CustomerDALC 對象並嘗試調用它的 DeleteCustomer 方法
// 僅在當前當事人的身份標識和角色合格時這一步驟才能成功
CustomerDALC c = new CustomerDALC();
cDeleteCustomer(VINET);
}
}

  Windows 身份驗證   

  理想情況下在連接到數據庫時應使用 Windows 身份驗證而不是 SQL Server 身份驗證然而應使用服務帳戶並避免模擬連接到數據庫因為它會妨礙連接池連接池需要相同的連接字符串如果嘗試使用不同的連接字符串打開數據庫就會創建單獨的連接池而這將限制可縮放性

  安全通信建議

  要實現調用應用程序與數據訪問邏輯組件之間的安全通信請考慮以下建議
如果數據訪問邏輯組件是通過各種層的線路調用的並且信息交換包含需要保護的機密信息則應使用分布式組件對象模型 (DCOM)安全套接字層 (SSL)安全 Internet 協議 (IPSec) 等安全通信技術
如果數據是加密存儲在數據庫中則通常由數據訪問邏輯組件負責數據的加密與解密如果信息暴露會導致巨大損害則必須考慮保護與數據訪問邏輯組件進行通信的通道

  業務實體組件中的安全性建議

  如果將業務實體實現為數據結構(如 XML 或 DataSet)則不需要實現安全性檢查然而如果將業務實體實現為帶有 CRUD 操作的自定義業務實體組件請考慮以下建議
如果將實體提供給您不完全信任的業務過程應在業務實體組件和數據訪問邏輯組件中實現授權檢查然而如果在這兩個層次上都實現檢查可能會產生保持安全性策略同步的維護問題
業務實體組件不應處理通信安全性或數據加密應把這些任務留給相應的數據訪問邏輯組件

  部署

  本節提供一些建議以幫助您確定如何部署數據訪問邏輯組件和業務實體組件

  部署數據訪問邏輯組件

  部署數據訪問邏輯組件的方法有兩種
與業務過程對象一起部署數據訪問邏輯組件這種部署方法具有最佳的數據傳輸性能還有一些額外的技術優勢
事務處理可以在業務過程對象和數據訪問邏輯組件之間無縫流動然而事務處理不能跨越遠程通道無縫流動在遠程方案下需要使用 DCOM 來實現事務處理此外如果業務過程與數據訪問邏輯組件被防火牆分開還需要打開這兩個物理層之間的防火牆端口以啟用 DTC 通信
一起部署業務過程對象和數據訪問邏輯組件可以減少事務處理失敗節點的數目
安全性環境自動在業務過程對象和數據訪問邏輯組件之間流動無需設置當事人對象
與用戶界面代碼一起部署數據訪問邏輯組件有時需要直接從 UI 組件和 UI 過程組件使用數據訪問邏輯組件為提高 Web 方案下的性能可以與 UI 代碼一起部署數據訪問邏輯組件這種部署方法可以使 UI 層充分利用數據讀取器流以獲得最佳性能然而在使用這種部署方法時必須牢記以下事項
不與 UI 代碼一起部署數據訪問邏輯組件的一個常見原因是防止通過 Web 領域直接對數據源進行網絡訪問
如果您的 Web 領域部署在 DMZ 環境中則必須打開防火牆端口才能訪問 SQL Server如果使用 COM+ 事務處理還必須為 DTC 通信打開其他的防火牆端口

  部署業務實體

  應用程序的許多不同層都要使用業務實體根據業務實體的實現方式如果您的應用程序跨越各個物理層則需要將業務實體部署到多個位置下面列出了在不同實現方案中部署業務實體的方法
部署作為有類型的 DataSet 實現的業務實體有類型的 DataSet 類必須由數據訪問邏輯組件和調用應用程序訪問因此建議在一個要部署在多個層的公共程序集中定義有類型的 DataSet 類
部署作為自定義業務實體組件實現的業務實體根據數據訪問邏輯組件中定義的方法簽名自定義實體類可能需要由數據訪問邏輯組件訪問請遵循與有類型的 DataSet 相同的建議即在一個要部署在多個層的公共程序集中定義自定義實體類
部署作為通用 DataSet 或 XML 字符串實現的業務實體通用 DataSet 和 XML 字符串不表示單獨的數據類型以這兩種格式實現的業務實體不存在部署問題

  如何定義數據訪問邏輯組件類

  以下代碼示例定義一個名為 CustomerDALC 的類它是用於 Customer 業務實體的數據訪問邏輯組件類CustomerDALC 類為 Customer 業務實體實現 CRUD 操作並提供了其他方法為此對象封裝業務邏輯

   public class CustomerDALC
{
private string conn_string;

  public CustomerDALC()
{
// 從安全或加密的位置獲取連接字符串
// 並將其分配給 conn_string
}

  public CustomerDataSet GetCustomer(string id)
{
// 檢索包含 Customer 數據的有類型的 DataSet
}

  public string CreateCustomer(string name
string address string city string state
string zip)
{
// 根據傳遞給此方法的標量參數在數據庫中創建一個
// 新客戶
// 從此方法返回 customerID
}

  public void UpdateCustomer(CustomerDataSet updatedCustomer)
{
// 根據作為類型 CustomerDataSet 的參數發送的 Customer 數據更新
// 數據庫
}

  public void DeleteCustomer(string id)
{
// 刪除具有指定 ID 的客戶
}

  public DataSet GetCustomersWhoPurchasedProduct(int productID)
{
// 使用通用 DataSet 檢索客戶因為此方法
// 不需要檢索與客戶關聯的全部信息
}
}

  如何使用 XML 表示數據的集合和層次結構

  以下示例顯示了如何在 XML 文檔中表示數據的集合和層次結構該 XML 文檔表示客戶的一個訂單注意元素 <OrderDetails> 包含一個該訂單的詳細信息集合

   <Order xmlns=urn:aUniqueNamespace
<OrderID></OrderID>
<CustomerID>VINET</CustomerID>
<OrderDate></OrderDate>
<ShippedDate></ShippedDate>
<OrderDetails>
<OrderDetail>
<ProductID></ProductID>
<UnitPrice></UnitPrice>
<Quantity></Quantity>
</OrderDetail>
<OrderDetail>
<ProductID></ProductID>
<UnitPrice></UnitPrice>
<Quantity></Quantity>
</OrderDetail>
<OrderDetail>
<ProductID></ProductID>
<UnitPrice></UnitPrice>
<Quantity></Quantity>
</OrderDetail>
</OrderDetails>
</Order>

  如何在 應用程序中編程應用樣式表

  要在 NET 應用程序中編程應用樣式表請執行以下步驟


    導入 SystemXmlXsl 命名空間如以下代碼所示SystemXmlXsl 命名空間包含 NET Framework 類庫中的 XSLT 轉換類

    using SystemXmlXsl;


    創建一個 XslTransform 對象如以下代碼所示
    XslTransform stylesheet = new XslTransform();


    將所需樣式表加載到 XslTransform 對象如以下代碼所示
    stylesheetLoad(MyStylesheetxsl);


    調用 XslTransform 對象的 Transform 方法如以下代碼所示調用 Transform 方法指定 XML 源文檔和結果文檔的名稱

    stylesheetTransform(sourceDoc resultDoc);

    如何創建有類型的 DataSet

  可以使用有類型的 DataSet 表示業務實體創建有類型的 DataSet 的方法有多種
從 Microsoft Visual Studio ®NET 中的數據適配器創建
從 Visual Studio NET 中的 XSD 架構文件創建
使用 XSD 架構定義工具 (xsdexe) 從 NET Framework 命令提示窗口創建

注意也可以編程定義有類型的 DataSet即從 DataSet 繼承並定義方法屬性和嵌套類以表示該 DataSet 的結構最簡單的方法是使用以下過程之一創建一個有類型的 DataSet然後將此有類型的 DataSet 類用作將來您自己的有類型的 DataSet 類的基礎

    使用數據適配器創建有類型的 DataSet

  要使用數據適配器創建有類型的 DataSet請執行以下步驟


    在 Visual Studio NET 中向您的窗體或組件添加一個數據適配器在數據適配器的配置向導中指定該數據適配器的連接信息同時根據具體情況為數據適配器的 SelectInsertUpdate 和 Delete 命令指定 SQL 字符串或存儲過程
    在組件設計器中在數據適配器對象上單擊鼠標右鍵然後單擊 Generate DataSet(生成 DataSet)
    在 Generate DataSet(生成 DataSet)對話框中單擊 New(新建)鍵入新 DataSet 類的名稱然後單擊 OK(確定)
    為確認已創建該有類型的 DataSet可以在解決方案資源管理器中單擊 Show All Files(顯示所有文件)按鈕展開 XSD 架構文件的節點確認存在一個與 XSD 架構相關聯的代碼文件該代碼文件定義了新的有類型的 DataSet 類

  從 XSD 架構文件創建有類型的 DataSet

  要使用 Visual Studio NET 從 XSD 架構文件創建有類型的 DataSet請執行以下步驟


    在 Visual Studio NET中創建一個新項目或打開一個現有項目
    為項目添加一個現有的 XSD 架構或在組件設計器中創建一個新的 XSD 架構
    在解決方案資源管理器中雙擊 XSD 架構文件在組件設計器中查看該 XSD 架構
    在組件設計器中選擇主 XSD 架構元素
    在 Schema(架構)菜單中單擊 Generate DataSet(生成 DataSet)
    為確認已創建該有類型的 DataSet可以在解決方案資源管理器中單擊 Show All Files(顯示所有文件)按鈕展開 XSD 架構文件的節點確認存在一個與 XSD 架構相關聯的代碼文件該代碼文件定義了新的有類型的 DataSet 類

  使用 XSD 架構定義工具 (xsdexe) 創建有類型的 DataSet

  XML 架構定義工具可以從 XSD 架構文件XDR 架構文件或 XML 實例文檔生成有類型的 DataSet以下命令使用名為 XsdSchemaFilexsd 的 XSD 架構文件在當前目錄中名為 XsdSchemaFilecs 的 Visual C# 源文件中生成一個有類型的 DataSet

  xsd /dataset /language:C# XsdSchemaFilexsd

  如何定義業務實體組件

  以下示例顯示了如何為 Product 業務實體定義自定義實體類

  

  public class ProductEntity
{
// 專用字段用於保存 Product 實體的狀態
private int productID;
private string productName;
private string quantityPerUnit;
private decimal unitPrice;
private short unitsInStock;
private short unitsOnOrder;
private short reorderLevel;

  // 公共屬性用於公開 Product 實體的狀態
public int ProductID
{
get { return productID; }
set { productID = value; }
}
public string ProductName
{
get { return productName; }
set { productName = value; }
}
public string QuantityPerUnit
{
get { return quantityPerUnit; }
set { quantityPerUnit = value; }
}
public decimal UnitPrice
{
get { return unitPrice; }
set { unitPrice = value; }
}
public short UnitsInStock
{
get { return unitsInStock; }
set { unitsInStock = value; }
}
public short UnitsOnOrder
{
get { return unitsOnOrder; }
set { unitsOnOrder = value; }
}
public short ReorderLevel
{
get { return reorderLevel; }
set { reorderLevel = value; }
}

  // 執行本地化處理的方法和屬性
public void IncreaseUnitPriceBy(decimal amount)
{
unitPrice += amount;
}
public short UnitsAboveReorderLevel
{
get { return (short)(unitsInStock reorderLevel); }
}
public string StockStatus
{
get
{
return 庫存+ unitsInStock + 訂購 + unitsOnOrder;
}
}
}

  如何表示業務實體組件中數據的集合和層次結構

  以下示例顯示了如何為 Order 業務實體定義自定義實體類每個訂單都包含許多訂購項目這些訂購項目保存在 OrderEntity 類的一個 DataSet 中

  

  public class OrderEntity
{
// 專用字段用於保存訂單信息
private int orderID;
private string customerID;
private DateTime orderDate;
private DateTime shippedDate;

  // 專用字段用於保存訂單詳細信息
private DataSet orderDetails;

  // 公共屬性用於提供訂單信息
public int OrderID
{
get { return orderID; }
set { orderID = value; }
}
public string CustomerID
{
get { return customerID; }
set { customerID = value; }
}
public DateTime OrderDate
{
get { return orderDate; }
set { orderDate = value; }
}
public DateTime ShippedDate
{
get { return shippedDate; }
set { shippedDate = value; }
}

  // 公共屬性用於提供訂單詳細信息
public DataSet OrderDetails
{
get { return orderDetails; }
set { orderDetails = value; }
}

  // 附加方法用於簡化對訂單詳細信息的訪問
public bool IsProductOrdered(int productID)
{
// 必須在 DataTable 中定義主關鍵字列
DataRow row = orderDetailsTables[]RowsFind(productID);

if (row != null)
return true;
else
return false;
}

  // 附加屬性用於簡化對訂單詳細信息的訪問
public int NumberOfOrderItems
{
get
{
return orderDetailsTables[]RowsCount;
}
}
}

  關於 OrderEntity 類請注意以下幾點


該類包含用於保存有關訂單的信息的專用字段還有一個專用 DataSet 字段用於保存訂單的其他詳細信息數據訪問邏輯組件將在創建 OrderEntity 對象時填充所有這些字段
該類包含用於提供有關訂單的信息的公共屬性此外還有一個用於提供該 DataSet 的屬性以便使調用應用程序能夠訪問訂單詳細信息
該類包含一個附加方法和一個附加屬性用於簡化對訂單詳細信息的訪問
IsProductOrdered 方法接收一個 ProductID 參數並返回一個布爾值以表明該產品是否出現在訂單中
NumberOfOrderItems 屬性表明訂單中的訂購行數目

    如何將業務實體組件綁定到用戶界面控件

  可以將用戶界面控件綁定到 Windows 窗體和 ASPNET 應用程序中的自定義實體有兩種可能的方案
在用戶界面控件上綁定單個業務實體以下代碼示例顯示了如何從 OrderDALC 對象獲取一個 OrderEntity 對象並將其綁定到 Windows 窗體的控件上當用戶更改這些控件中的值時基礎 OrderEntity 對象中的數據也將自動更改 // 創建 OrderDALC 對象

OrderDALC dalcOrder = new OrderDALC();

  // 使用 dalcOrder 為訂單 ID 獲取一個 OrderEntity 對象
// 此代碼假設 OrderDALC 類有一個名為 GetOrder() 的方法
// 該方法為特定訂單 ID 返回一個 OrderEntity 對象
OrderEntity order = dalcOrderGetOrder();

  // 將 OrderEntity 的 OrderID 屬性綁定到 TextBox 控件
textBoxDataBindingsAdd(Text order OrderID);

  // 將 OrderEntity 的 CustomerID 屬性綁定到另一個 TextBox 控件
control
textBoxDataBindingsAdd(Text order CustomerID);

  // 將 OrderEntity 的 OrderDate 屬性綁定到 DatePicker 控件
dateTimePickerDataBindingsAdd(Value order OrderDate);

  // 將 OrderEntity 的 ShippedDate 屬性綁定到另一個 DatePicker 控件
dateTimePickerDataBindingsAdd(Value order ShippedDate);

  // 將 OrderEntity 的 OrderDetails DataSet 綁定到 DataGrid 控件
// DataGrid 分別用網格中的一行顯示 DataSet 的各個 DataRow
dataGridDataSource = orderOrderDetailsTables[]DefaultView;

  准備好後您可以將修改後的 OrderEntity 對象傳遞給 OrderDALC以便將數據保存到數據庫中如以下代碼所示

  // 通過 dalcOrder 將 OrderEntity 對象保存到數據庫中
// 此代碼假設 OrderDALC 類有一個名為 UpdateOrder() 的方法
// 該方法接收一個 OrderEntity 參數並更新數據庫中的相應項
dalcOrderUpdateOrder(order);


將業務實體集合綁定到 DataGrid 控件以下代碼示例顯示了如何從 OrderDALC 獲取一個 OrderEntity 對象數組並將其綁定到 Windows 窗體的 DataGrid 控件DataGrid 分別用網格中的一行顯示每個數組元素(即每個 OrderEntity 對象) // 創建 OrderDALC 對象
OrderDALC dalcOrder = new OrderDALC();

  // 使用 dalcOrder 獲取客戶VINET的 OrderEntity 對象數組
// 此代碼假設 OrderDALC 類有一個名為
GetOrdersForCustomer()
// 的方法該方法返回特定客戶的 OrderEntity 對象數組
OrderEntity[] orderEntities = dalcOrderGetOrdersForCustomer(VINET);

  // 將該數組綁定到 DataGrid 控件
dataGridDataSource = orderEntities;

  准備好後您可以將修改後的數組傳遞給 OrderDALC以便將數據保存到數據庫中如以下代碼所示

  // 通過 dalcOrder 將 OrderEntity 對象保存到數據庫中
// 此代碼假設 OrderDALC 類有一個名為 UpdateOrder() 的方法該方法獲取
// 一個 OrderEntity 對象數組並更新數據庫中的相應項
dalcOrderUpdateOrders(orderEntities);

    如何在業務實體組件中提供事件

  自定義實體可以在業務實體狀態修改時產生事件這些事件可用於獲得豐富的客戶端用戶界面設計因為這使得無論數據顯示在哪裡都可以對其進行刷新以下代碼示例顯示了如何在 OrderEntity 類中產生業務實體相關事件

  

  // 為所有業務實體事件定義公用事件類
public class EntityEventArgs : EventArgs
{
// 定義事件成員用於提供有關事件的信息
}

  // 定義一個代理用於為業務實體相關事件指定簽名
public delegate void EntityEventHandler(Object source EntityEventArgs e);

  // 定義自定義實體類它可以在業務實體狀態改變時產生事件
public class OrderEntity
{
// 定義業務實體狀態改變的before事件和after事件
public event EntityEventHandler BeforeChange AfterChange;

  // 專用字段用於保存業務實體的狀態
private int orderID;
private int customerID;
private DateTime orderDate;
private DateTime shippedDate;
private DataSet orderDetails;

  // 公共屬性用於提供業務實體的狀態
public int OrderID
{
get { return orderID; }
set
{
BeforeChange(this new EntityEventArgs()); // 產生before事件
orderID = value;
AfterChange(this new EntityEventArgs()); // 產生after事件
}
}
public int CustomerID
{
get { return customerID; }
set
{
BeforeChange(this new EntityEventArgs()); // 產生before事件
customerID = value;
AfterChange(this new EntityEventArgs()); // 產生after事件
}
}
public DateTime OrderDate
{
get { return orderDate; }
set
{
BeforeChange(this new EntityEventArgs()); // 產生before事件
orderDate = value;
AfterChange(this new EntityEventArgs()); // 產生after事件
}
}
public DateTime ShippedDate
{
get { return shippedDate; }
set
{
BeforeChange(this new EntityEventArgs()); // 產生before事件
shippedDate = value;
AfterChange(this new EntityEventArgs()); // 產生after事件
}
}

  // 必要時使用更多成員
}

  關於上述代碼請注意以下幾點

  EntityEvent 類提供有關業務實體相關事件的信息EntityEventHandler 代理為自定義實體類產生的所有業務實體相關事件指定簽名該代理簽名遵循所建議的 NET Framework 事件處理程序代理的原則

  OrderEntity 類定義了兩個名為 BeforeChange 和 AfterChange 的事件

  OrderEntity 中的屬性設置器在業務實體狀態改變前產生一個 BeforeChange 事件在業務實體狀態改變後產生一個 AfterChange 事件

  如何將業務實體組件序列化為 XML 格式

  本節討論以下問題

  使用 XmlSerializer 序列化自定義實體對象

  XML Web Services 中對象的 XML 序列化

  序列化自定義實體對象的默認 XML 格式

  控制序列化自定義實體對象的 XML 格式

  使用 XmlSerializer 序列化自定義實體對象

  以下代碼示例顯示了如何使用 XmlSerializer 類將 OrderEntity 對象序列化為 XML 格式

  

  using SystemXmlSerialization; // 此命名空間包含 XmlSerializer 類

// 創建一個 XmlSerializer 對象用於序列化 OrderEntity 類型的對象
XmlSerializer serializer = new XmlSerializer(typeof(OrderEntity));

  // 將 OrderEntity 對象序列化為名為MyXmlOrderEntityxml的 XML 文件
TextWriter writer = new StreamWriter(MyXmlOrderEntityxml);
serializerSerialize(writer order);
writerClose();

  在 XML Web services 中序列化對象

  以下代碼示例顯示了如何編寫使用自定義實體對象的 XML Web services

  

  namespace MyWebService
{
[WebService(Namespace=urn:MyWebServiceNamespace)]
public class OrderWS : SystemWebServicesWebService
{
[WebMethod]
public OrderEntity GetOrder(int orderID)
{
// 創建 OrderDALC 對象
OrderDALC dalcOrder = new OrderDALC();

  // 使用 dalcOrder 獲取指定訂單 ID 的 OrderEntity 對象
// 此代碼假設 OrderDALC 類有一個名為 GetOrder 的方法
// 該方法獲取一個訂單 ID 作為參數並返回一個 OrderEntity 對象
// 其中包含該訂單的所有數據
OrderEntity order = dalcOrderGetOrder();

  // 返回 OrderEntity 對象 該對象將自動序列化
return order;
}

  [WebMethod]
public void UpdateOrder(OrderEntity order)
{
// 創建 OrderDALC 對象
OrderDALC dalcOrder = new OrderDALC();

  // 使用 dalcOrder 將 OrderEntity 對象的數據保存到數據庫中
// 此代碼假設 OrderDALC 類有一個名為 UpdateOrder 的方法
// 該方法接收一個 OrderEntity 對象並將數據保存到數據庫中
dalcOrderUpdateOrder(order);
}

  關於上述代碼請注意以下幾點

  GetOrder 方法接收一個訂單 ID 作為參數並返回包含該訂單的數據的 OrderEntity 對象

  UpdateOrder 方法接收一個 OrderEntity 對象並將該對象的數據保存到數據庫中

  如果客戶端應用程序調用 GetOrder 和 UpdateOrder 方法OrderEntity 對象將為該方法調用自動序列化為 XML 格式

  序列化自定義實體對象的默認 XML 格式

  以下 XML 文檔顯示了 OrderEntity 對象的默認 XML 序列化格式

   <?xml version= encoding=utf?>
<OrderEntity xmlns:xsd=
xmlns:xsi=instance
<OrderID></OrderID>
<CustomerID>VINET</CustomerID>
<OrderDate>T::+:</OrderDate>
<OrderDetails> see below </OrderDetails>
<ShippedDate>T::+:</ShippedDate>
</OrderEntity>

  上述文檔說明了 XML 序列化的默認規則

  該 XML 文檔的根元素與類名稱 OrderEntity 相同

  OrderEntity 對象中的每個公共屬性(及字段)都被序列化為具有相同名稱的元素

  OrderEntity 類中的 OrderDetails 屬性是一個 DataSetDataSet 提供了內置的 XML 序列化支持OrderDetails DataSet 的序列化結果如下

   <OrderDetails>
<xs:schema id=NewDataSet xmlns=
xmlns:xs=
xmlns:msdata=urn:schemasmicrosoftcom:xmlmsdata
<xs:element name=NewDataSet msdata:IsDataSet=true msdata:Locale=en
UK
<xs:complexType>
<xs:choice maxOccurs=unbounded
<xs:element name=OrderDetails
<xs:complexType>
<xs:sequence>
<xs:element name=OrderID type=xs:int minOccurs= />
<xs:element name=ProductID type=xs:int minOccurs= />
<xs:element name=UnitPrice type=xs:decimal minOccurs=
/>
<xs:element name=Quantity type=xs:short minOccurs= />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:choice>
</xs:complexType>
</xs:element>
</xs:schema>
<diffgr:diffgram xmlns:msdata=urn:schemasmicrosoftcom:xmlmsdata
xmlns:diffgr=urn:schemasmicrosoftcom:xmldiffgramv
<NewDataSet>
<OrderDetails diffgr:id=OrderDetails msdata:rowOrder=
diffgr:hasChanges=inserted
<OrderID></OrderID>
<ProductID></ProductID>
<UnitPrice></UnitPrice>
<Quantity></Quantity>
</OrderDetails>
<OrderDetails diffgr:id=OrderDetails msdata:rowOrder=
diffgr:hasChanges=inserted
<OrderID></OrderID>
<ProductID></ProductID>
<UnitPrice></UnitPrice>
<Quantity></Quantity>
</OrderDetails>
<OrderDetails diffgr:id=OrderDetails msdata:rowOrder=
diffgr:hasChanges=inserted
<OrderID></OrderID>
<ProductID></ProductID>
<UnitPrice></UnitPrice>
<Quantity></Quantity>
</OrderDetails>
</NewDataSet>
</diffgr:diffgram>
</OrderDetails>

  關於 DataSet 的序列化請注意以下幾點

  <xs:schema> 段描述了 DataSet 的結構包括表列名稱和列類型

  <xs:diffgram> 段包含該 DataSet 的數據每個 <OrderDetails> 元素表示該 DataSet 中 OrderDetails 表中的單獨一行

  控制序列化自定義實體對象的 XML 格式

  您可以在自定義實體類中使用 NET 屬性來控制屬性和字段序列化為 XML 的方式請考慮以下修訂後的 OrderEntity 類

  

  [XmlRoot(ElementName=Order Namespace=urn:MyNamespace)]
public class OrderEntity
{
[XmlAttribute(AttributeName=ID)]
public int OrderID {獲取和設置代碼同前}

  [XmlAttribute(AttributeName=CustID)]
public string CustomerID {獲取和設置代碼同前}

  [XmlElement(ElementName=Ordered)]
public DateTime OrderDate {獲取和設置代碼同前}

  public DataSet OrderDetails {獲取和設置代碼同前}

  [XmlElement(ElementName=Shipped)
public DateTime ShippedDate {獲取和設置代碼同前}

  // 必要時使用更多成員
}

  將 OrderEntity 對象序列化為 XML 後其格式如下

   <?xml version= encoding=utf ?>
<Order ID=
CustID=VINET
xmlns=urn:MyNamespace
xmlns:xsd=
xmlns:xsi=instance
<Ordered>T::+:</Ordered>
<OrderDetails>詳細代碼同前</OrderDetails>
<Shipped>T::+:</Shipped>
</Order>

  如何將業務實體組件序列化為 SOAP 格式

  以下代碼示例顯示了如何使用 SoapFormatter 類將 OrderEntity 對象序列化為 SOAP 格式當使用 SOAP 協議向或從 XML Web services 傳遞對象或者當使用 HTTP 遠程通道向或從 Remoting 服務器傳遞對象時也會發生 SOAP 序列化(隱式)此外您也可以在使用 TCP 遠程通道時指定 SOAP 格式化

  

  using SystemRuntimeSerializationFormattersSoap; // 用於 SoapFormatter 類

// 創建 SoapFormatter 對象用於序列化 OrderEntity 類型的對象
SoapFormatter formatter = new SoapFormatter();

  // 將 OrderEntity 對象序列化為名為MySoapOrderEntityxml的 SOAP (XML) 文件
FileStream stream = FileCreate(MySoapOrderEntityxml);
formatterSerialize(stream order);
streamClose();

  要對自定義實體組件使用 SOAP 序列化必須使用 Serializable 屬性注釋您的實體類如以下代碼所示

   [Serializable]
public class OrderEntity
{
// 成員同前

  如果要自定義序列化過程中生成的 SOAP 格式實體類必須實現 ISerializable 接口您必須提供一個 GetObjectData 方法供 SoapFormatter 在序列化過程中調用並提供一個特殊構造函數供 SoapFormatter 在還原序列化過程中調用以重新創建對象以下代碼顯示了 ISerializable 接口GetObjectData 方法和特殊構造函數的使用

  

  using SystemRuntimeSerialization; // 用於 ISerializable 接口以及相關類型

[Serializable]
public class OrderEntity : ISerializable
{
// 序列化函數由 SoapFormatter 在序列化過程中調用
void ISerializableGetObjectData(SerializationInfo info StreamingContext
ctxt)
{
// 向 SerializationInfo 對象中添加每個字段
infoAddValue(OrderID orderID);
// 必要時使用更多代碼
}

  // 還原序列化構造函數由 SoapFormatter 在還原序列化過程中調用
public OrderEntity(SerializationInfo info StreamingContext ctxt)
{
// 從 SerializationInfo 對象中還原序列化出各個 OrderEntity 字段
orderID = (int)infoGetValue(OrderID typeof(int));
// 必要時使用更多代碼
}

// 其他成員同前
}

    如何將業務實體組件序列化為二進制格式

  以下代碼示例顯示了如何使用 BinaryFormatter 類將 OrderEntity 對象序列化為二進制格式當使用 TCP 遠程通道向或從 Remoting 服務器傳遞對象時也會發生二進制序列化(隱式)此外為提高性能您也可以在使用 HTTP 遠程通道時指定二進制格式化

  

  using SystemRuntimeSerializationFormattersBinary; // 用於 BinaryFormatter 類

// 創建 BinaryFormatter 對象用於序列化 OrderEntity 類型的對象
BinaryFormatter formatter = new BinaryFormatter();

  // 將 OrderEntity 對象序列化為名為MyBinaryOrderEntitydat的二進制文件
FileStream stream = FileCreate(MyBinaryOrderEntitydat);
formatterSerialize(stream order);
streamClose();

  要對自定義實體對象使用二進制序列化必須使用 Serializable 屬性注釋您的自定義實體類要自定義序列化過程中生成的二進制格式自定義實體類必須實現 ISerializable 接口這兩種方案中的詳細代碼與 SOAP 序列化的代碼相同


From:http://tw.wingwit.com/Article/program/net/201311/12470.html
    推薦文章
    Copyright © 2005-2013 電腦知識網 Computer Knowledge   All rights reserved.