ASP.NET2.0ObjectDataSource控件
ObjectDataSource控件與SqlDataSource控件的對象模型是類似的。ObjectDataSource沒有ConnectionString屬性,它暴露了TypeName屬性,用于指定需要實例化的執行數據操作的對象類型(類名)。ObjectDataSource控件與SqlDataSource的命令屬性相似,也支持SelectMethod、UpdateMethod、InsertMethod和DeleteMethod等屬性,用于指明執行這些數據操作的關聯類型的方法。本文將解釋建立數據訪問層和業務邏輯層組件,并通過ObjectDataSource對象展示ASP.NET 2.0數據組件的技術。
綁定到數據訪問層
數據訪問層組件封裝了那些使用SQL命令查詢和修改數據庫的ADO.NET代碼。在典型情況下,它抽象了建立ADO.NET連接和命令的細節信息,暴露了可以通過適當參數調用的方法。典型的數據訪問層組件可能暴露了下面一些方法:
ObjectDataSource可以使用下面的方式來關聯到這個類型:
ObjectDataSource要求對象有非常特殊的設計模式。這些約束都是Web應用程序請求所處的無狀態的(stateless)環境引起的。由于在典型情況下,對象的建立和銷毀都是為了服務于一個請求,因此通過對象數據源綁定的對象也是無狀態的。在默認情況下,ObjectDataSource采用TypeName屬性指定的類型的默認的構造函數(不帶參數),盡管通過處理ObjectCreating事件來建立一個自定義對象實例,并把它指定給事件參數的ObjectInstance屬性,從而實現實例化也是可行的。與SelectMethod屬性關聯的對象方法可以返回任何對象、Ienumerable列表、集合或數組。在上面的數據訪問層示例中,DataView對象實現了IEnumerable接口。我們在下一部分將討論到,這些方法也可以返回強化類型的集合或對象。
Update、Insert和Delete一般把單獨的數據項字段作為參數,也可以把帶有數據項字段公共屬性的集合類對象作為參數。
與SqlDataSource的例子類似,傳遞到Update、Insert和Delete方法的數據項的參數名稱或屬性必須與SelectMethod返回的字段相同,這樣GridView/DetailsView才能自動地進行更新/刪除/插入操作。與SqlDataSource類似,ObjectDataSource方法的參數也可以與數據參數對象相關聯,使用SelectParameters、FilterParameters、UpdateParameters、DeleteParameters或InsertParameters集合。
下面的例子演示了一個通過數據訪問層組件(AuthorsDB)暴露數據的ObjectDataSource控件。這個類型的類文件存放在應用程序的App_Code目錄中,在運行時ASP.NET動態地編譯它。
綁定到業務邏輯層
關于數據訪問層,我們還需要重點的注意的是,由于SelectMethod把執行查詢的結果作為數據視圖返回,它仍然把下層數據庫的大綱暴露給了顯示頁面。還有,在數據訪問層沒有業務規則;它只是簡單地執行查詢和返回結果。如果需要把顯示與數據庫大綱隔離開來,并引入業務規則或驗證過程,通常需要把數據訪問層包裝到業務邏輯層中。
業務邏輯層與DAL類似,它給ObjectDataSource暴露了無狀態的方法,用于綁定Web頁面中的控件。但是,它一般不會直接返回ADO.NET結果,而是返回強化類型的對象,這些對象表現了應用程序所使用的業務實體。這種顯示層與下層數據存儲大綱的分離,使我們更容易地單獨維護站點中的數據訪問部分,而不用修改使用數據的頁面。只要有恰當的中間層,你就可以全面修改下層數據存儲大綱,而不用更新應用程序中的獨立頁面。
下面就是一個業務邏輯層的例子。
業務邏輯層和數據訪問層之間的主要區別在于,業務邏輯層返回的是強化類型的Record對象的集合(RecordCollection),而不是數據視圖。它也允許我們把這個Record對象作為參數進行更新、插入和刪除操作。ObjectDataSource的DataObjectTypeName屬性允許你配置ObjectDataSource,給它傳遞類型而不是字段值。在業務邏輯層的方法實現中,你可以包含用于驗證業務規則的自定義邏輯。例如,你可以確保只有“檢查中”類別的Record才能被更新,或者只有Administrators才能插入新記錄。你還可以包含驗證邏輯以確保在插入或修改數據庫的數據之前,作為參數傳遞進來的數據類型和值是正確的。請注意,業務邏輯層中的驗證規則不是顯示層的輸入驗證(它指導終端用戶在提交更新之前輸入正確的值)的替代品。
下面的例子演示了一個叫做AuthorsComponent的簡單業務邏輯層。在它內部,BLL通過DAL調用來實際執行數據庫操作。為了簡單,BLL沒有包含任何業務規則或驗證,盡管它可能是一個現實的應用程序。我們還要注意,這個例子沒有通過編寫自定義集合類來返回強化類型的記錄,而是利用了.NET框架組件2.0中的稱為“范型(Generics)”的新語言特性來建立Author對象集合。使用強化類型集合讓ObjectDataSource在設計時(在Visual Studio和其它工具中)能夠推導出業務對象的大綱。
下面的圖表顯示了GridView、ObjectDataSource和業務邏輯層之間的交互操作。ObjectDataSource被配置為調用ContactsList類型的GetContacts方法,返回Contact對象的集合。GridView列出了Contact對象,并直接綁定到該類型的屬性(ID, Name)來生成列。請注意,SelectMethod可以返回一個Contact對象的IEnumerable接口,或者返回單個Contact對象。如果本身沒有實現IEnumerable,ObjectDataSource會把SelectMethod返回的結果封裝到IEnumerable中。
ObjectDataSource控件與SqlDataSource類似,當SelectMethod 返回數據集、數據視圖或數據表對象的時候,它也支持排序功能。ObjectDataSource依賴數據視圖。在這個例子中Sort屬性執行排序操作。ObjectDataSource也支持SelectMethod實現中的自定義排序,如果該方法沒有返回數據集、數據視圖和數據表,它就非常有用。通過把SortParameterName屬性設置為從數據源接受SortExpression的方法參數名稱,可以實現自定義排序。在調用SelectMethod的時候,ObjectDataSource會把這個表達式傳遞到你的方法中,你就可以使用這個表達式實現自己的排序邏輯。前面的例子演示了在AuthorsComponent類中自定義了一個排序實現。
ObjectDataSource還支持SelectMethod實現中的自定義分頁功能。你需要使用StartRowIndexParameterName、MaximumRowsParameterName和SelectCountMethod屬性來設置它。
綁定到Visual Studio數據集
綁定數據訪問層的操作可能很單調乏味,因為在DAL的不同方法中,執行SQL語句或存儲過程的ADO.NET代碼時相同的或相似的。雖然你可以利用上述技術數用定制的ADO.NET代碼來編寫自己的DAL,Visual Studio還是提供了一條基于簡單的向導生成數據訪問層的方便途徑。在這種情況下,數據訪問層是強化類型的數據集對象。該數據集包含了TableAdapter類型,它暴露了用于返回強化類型的數據表對象的方法。這些方法適合于直接綁定到ObjectDataSource,或者在業務邏輯層組件中調用。
為了給Visual Studio對象添加數據集,你需要右鍵點擊“解決方案瀏覽器”并選擇“添加新項”,接著選擇“數據集”項類型。Visual Studio給App_Code目錄添加了一個DataSet.xsd文件,并打開了數據集設計器,載入了TableAdapter向導。你可以跟隨TableAdapter向導,指定數據庫中的SQL語句或存儲過程,接著在向導的最后一個頁面中輸入與這些查詢/命令關聯的方法名稱。
TableAdapter可以暴露兩個方法:Fill方法用于填充已有的數據集,Get方法返回一個已經填充好的數據表對象。前者更適合于Windows客戶端(在應用程序的生命周期中數據集保存在內存中),而后者適合于ObjectDataSource。TableAdapter向導還為你提供的SQL選擇語句自動地生成了更新、插入和刪除方法(需要選擇主鍵)。在配置好向導之后,Visual Studio給數據集設計器添加了一個新的數據表和TableAdapter類型。
TableAdapter描述了單個結果集的大綱和大綱上的選擇、更新、插入或刪除操作。你可以通過在數據集設計器中右鍵單擊,給數據集添加多個TableAdapter。你還可以右鍵點擊設計器中的TableAdapter框給TableAdapter添加額外的查詢(倘若它們返回相同的大綱)。例如,你的TableAdapter可能同時包含了GetAuthors()和GetAuthorsById(int id) 方法,但是如果要添加GetTitles()方法,可能需要添加一個新的TableAdapter。下圖顯示了添加了多個TableAdapter的數據集設計器:
你完成數據集的設計之后,就可以保存DataSet.xsd文件了(它引起該類型被設計器后臺編譯,以供頁面使用)。你可以看到暴露給頁面代碼的這些類型:
但是,你不需要從自己的代碼中調用這些方法。你可以把ObjectDataSource綁定到這些方法:
下面的例子演示了一個綁定到DataSet.TableAdapter方法的ObjectDataSource。在后面幾個例子中我們將使用這個數據集演示如何使用ASP.NET數據控件實現一個簡單的相冊應用程序。請注意這個例子中的數據視圖使用了一個叫做ImageField的新字段類型來顯示照片。我們還要注意,ObjectDataSource中使用的ConvertNullToDBNull會導致空參數值在傳遞給TableAdapter方法之前被轉換為DbNull(必須的)。
綁定到數據訪問層
數據訪問層組件封裝了那些使用SQL命令查詢和修改數據庫的ADO.NET代碼。在典型情況下,它抽象了建立ADO.NET連接和命令的細節信息,暴露了可以通過適當參數調用的方法。典型的數據訪問層組件可能暴露了下面一些方法:
| public class MyDataLayer { public DataView GetRecords(); public DataView GetRecordsByCategory(String categoryName); public DataView GetRecordByID(int recordID); public int UpdateRecord(int recordID, String recordData); public int DeleteRecord(int recordID); public int InsertRecord(int recordID, String recordData); } |
ObjectDataSource可以使用下面的方式來關聯到這個類型:
| <asp:ObjectDataSource TypeName="MyDataLayer" SelectMethod="GetRecords" UpdateMethod="UpdateRecord" DeleteMethod="DeleteRecord" InsertMethod="InsertRecord" runat="server"/> |
ObjectDataSource要求對象有非常特殊的設計模式。這些約束都是Web應用程序請求所處的無狀態的(stateless)環境引起的。由于在典型情況下,對象的建立和銷毀都是為了服務于一個請求,因此通過對象數據源綁定的對象也是無狀態的。在默認情況下,ObjectDataSource采用TypeName屬性指定的類型的默認的構造函數(不帶參數),盡管通過處理ObjectCreating事件來建立一個自定義對象實例,并把它指定給事件參數的ObjectInstance屬性,從而實現實例化也是可行的。與SelectMethod屬性關聯的對象方法可以返回任何對象、Ienumerable列表、集合或數組。在上面的數據訪問層示例中,DataView對象實現了IEnumerable接口。我們在下一部分將討論到,這些方法也可以返回強化類型的集合或對象。
| GetProducts() -> ProductCollection GetProductsDataSet() -> DataSet GetProduct (int productId) -> Product |
Update、Insert和Delete一般把單獨的數據項字段作為參數,也可以把帶有數據項字段公共屬性的集合類對象作為參數。
| UpdateProduct (int id, String name, double price, bool inStock) UpdateProduct (Product p) // p.ID, p.Name, p.Price, p.InStock DeleteProduct (int id) |
與SqlDataSource的例子類似,傳遞到Update、Insert和Delete方法的數據項的參數名稱或屬性必須與SelectMethod返回的字段相同,這樣GridView/DetailsView才能自動地進行更新/刪除/插入操作。與SqlDataSource類似,ObjectDataSource方法的參數也可以與數據參數對象相關聯,使用SelectParameters、FilterParameters、UpdateParameters、DeleteParameters或InsertParameters集合。
下面的例子演示了一個通過數據訪問層組件(AuthorsDB)暴露數據的ObjectDataSource控件。這個類型的類文件存放在應用程序的App_Code目錄中,在運行時ASP.NET動態地編譯它。
| <asp:ObjectDataSource ID="ObjectDataSource2" Runat="server" TypeName="AuthorsDB" SelectMethod="GetStates"/> <asp:ObjectDataSource ID="ObjectDataSource1" Runat="server" TypeName="AuthorsDB" SelectMethod="GetAuthorsByState" UpdateMethod="UpdateAuthor" OldValuesParameterFormatString="{0}"> <SelectParameters> <asp:ControlParameter Name="state" PropertyName="SelectedValue" ControlID="DropDownList1"/> </SelectParameters> </asp:ObjectDataSource> |
綁定到業務邏輯層
關于數據訪問層,我們還需要重點的注意的是,由于SelectMethod把執行查詢的結果作為數據視圖返回,它仍然把下層數據庫的大綱暴露給了顯示頁面。還有,在數據訪問層沒有業務規則;它只是簡單地執行查詢和返回結果。如果需要把顯示與數據庫大綱隔離開來,并引入業務規則或驗證過程,通常需要把數據訪問層包裝到業務邏輯層中。
業務邏輯層與DAL類似,它給ObjectDataSource暴露了無狀態的方法,用于綁定Web頁面中的控件。但是,它一般不會直接返回ADO.NET結果,而是返回強化類型的對象,這些對象表現了應用程序所使用的業務實體。這種顯示層與下層數據存儲大綱的分離,使我們更容易地單獨維護站點中的數據訪問部分,而不用修改使用數據的頁面。只要有恰當的中間層,你就可以全面修改下層數據存儲大綱,而不用更新應用程序中的獨立頁面。
下面就是一個業務邏輯層的例子。
| public class MyBusinessLayer { public RecordCollection GetRecords(); public RecordCollection GetRecordsByCategory(String categoryName); public RecordCollection GetRecordByID(int recordID); public String GetRecordName(int recordID); public Object GetRecordData(int recordID); public int UpdateRecord(Record r); public int DeleteRecord(Record r); public int InsertRecord(Record r); public int UpdateRecordData(int ID, String Data); public int UpdateRecordName(int ID, String Name); } public class Record { public int ID { get; set; } public String Name { get; set; } public Object Data { get; set; } } |
業務邏輯層和數據訪問層之間的主要區別在于,業務邏輯層返回的是強化類型的Record對象的集合(RecordCollection),而不是數據視圖。它也允許我們把這個Record對象作為參數進行更新、插入和刪除操作。ObjectDataSource的DataObjectTypeName屬性允許你配置ObjectDataSource,給它傳遞類型而不是字段值。在業務邏輯層的方法實現中,你可以包含用于驗證業務規則的自定義邏輯。例如,你可以確保只有“檢查中”類別的Record才能被更新,或者只有Administrators才能插入新記錄。你還可以包含驗證邏輯以確保在插入或修改數據庫的數據之前,作為參數傳遞進來的數據類型和值是正確的。請注意,業務邏輯層中的驗證規則不是顯示層的輸入驗證(它指導終端用戶在提交更新之前輸入正確的值)的替代品。
下面的例子演示了一個叫做AuthorsComponent的簡單業務邏輯層。在它內部,BLL通過DAL調用來實際執行數據庫操作。為了簡單,BLL沒有包含任何業務規則或驗證,盡管它可能是一個現實的應用程序。我們還要注意,這個例子沒有通過編寫自定義集合類來返回強化類型的記錄,而是利用了.NET框架組件2.0中的稱為“范型(Generics)”的新語言特性來建立Author對象集合。使用強化類型集合讓ObjectDataSource在設計時(在Visual Studio和其它工具中)能夠推導出業務對象的大綱。
| <asp:DropDownList ID="DropDownList1" Runat="server" DataSourceID="ObjectDataSource2" AutoPostBack="True" /> <asp:ObjectDataSource ID="ObjectDataSource2" Runat="server" TypeName="AuthorsComponent" SelectMethod="GetStates"/> <asp:GridView ID="GridView1" Runat="server" DataSourceID="ObjectDataSource1" AutoGenerateColumns="False" AllowPaging="True" AllowSorting="True"> …… </asp:GridView> <asp:ObjectDataSource ID="ObjectDataSource1" Runat="server" TypeName="AuthorsComponent" SelectMethod="GetAuthorsByState" UpdateMethod="UpdateAuthor" DataObjectTypeName="Author" SortParameterName="sortExpression"> …… </asp:ObjectDataSource> |
下面的圖表顯示了GridView、ObjectDataSource和業務邏輯層之間的交互操作。ObjectDataSource被配置為調用ContactsList類型的GetContacts方法,返回Contact對象的集合。GridView列出了Contact對象,并直接綁定到該類型的屬性(ID, Name)來生成列。請注意,SelectMethod可以返回一個Contact對象的IEnumerable接口,或者返回單個Contact對象。如果本身沒有實現IEnumerable,ObjectDataSource會把SelectMethod返回的結果封裝到IEnumerable中。
ObjectDataSource控件與SqlDataSource類似,當SelectMethod 返回數據集、數據視圖或數據表對象的時候,它也支持排序功能。ObjectDataSource依賴數據視圖。在這個例子中Sort屬性執行排序操作。ObjectDataSource也支持SelectMethod實現中的自定義排序,如果該方法沒有返回數據集、數據視圖和數據表,它就非常有用。通過把SortParameterName屬性設置為從數據源接受SortExpression的方法參數名稱,可以實現自定義排序。在調用SelectMethod的時候,ObjectDataSource會把這個表達式傳遞到你的方法中,你就可以使用這個表達式實現自己的排序邏輯。前面的例子演示了在AuthorsComponent類中自定義了一個排序實現。
ObjectDataSource還支持SelectMethod實現中的自定義分頁功能。你需要使用StartRowIndexParameterName、MaximumRowsParameterName和SelectCountMethod屬性來設置它。
綁定到Visual Studio數據集
綁定數據訪問層的操作可能很單調乏味,因為在DAL的不同方法中,執行SQL語句或存儲過程的ADO.NET代碼時相同的或相似的。雖然你可以利用上述技術數用定制的ADO.NET代碼來編寫自己的DAL,Visual Studio還是提供了一條基于簡單的向導生成數據訪問層的方便途徑。在這種情況下,數據訪問層是強化類型的數據集對象。該數據集包含了TableAdapter類型,它暴露了用于返回強化類型的數據表對象的方法。這些方法適合于直接綁定到ObjectDataSource,或者在業務邏輯層組件中調用。
為了給Visual Studio對象添加數據集,你需要右鍵點擊“解決方案瀏覽器”并選擇“添加新項”,接著選擇“數據集”項類型。Visual Studio給App_Code目錄添加了一個DataSet.xsd文件,并打開了數據集設計器,載入了TableAdapter向導。你可以跟隨TableAdapter向導,指定數據庫中的SQL語句或存儲過程,接著在向導的最后一個頁面中輸入與這些查詢/命令關聯的方法名稱。
TableAdapter可以暴露兩個方法:Fill方法用于填充已有的數據集,Get方法返回一個已經填充好的數據表對象。前者更適合于Windows客戶端(在應用程序的生命周期中數據集保存在內存中),而后者適合于ObjectDataSource。TableAdapter向導還為你提供的SQL選擇語句自動地生成了更新、插入和刪除方法(需要選擇主鍵)。在配置好向導之后,Visual Studio給數據集設計器添加了一個新的數據表和TableAdapter類型。
TableAdapter描述了單個結果集的大綱和大綱上的選擇、更新、插入或刪除操作。你可以通過在數據集設計器中右鍵單擊,給數據集添加多個TableAdapter。你還可以右鍵點擊設計器中的TableAdapter框給TableAdapter添加額外的查詢(倘若它們返回相同的大綱)。例如,你的TableAdapter可能同時包含了GetAuthors()和GetAuthorsById(int id) 方法,但是如果要添加GetTitles()方法,可能需要添加一個新的TableAdapter。下圖顯示了添加了多個TableAdapter的數據集設計器:
你完成數據集的設計之后,就可以保存DataSet.xsd文件了(它引起該類型被設計器后臺編譯,以供頁面使用)。你可以看到暴露給頁面代碼的這些類型:
| protected void Page_Load(object sender, EventArgs e) { DataSetTableAdapters.PhotosTableAdapter adapter = new DataSetTableAdapters.PhotosTableAdapter(); adapter.GetPhotosForAlbum(0); } |
但是,你不需要從自己的代碼中調用這些方法。你可以把ObjectDataSource綁定到這些方法:
| <asp:ObjectDataSource ID="ObjectDataSource1" runat="server" TypeName="DataSetTableAdapters.PhotosTableAdapter" SelectMethod="GetPhotosForAlbum"> <SelectParameters> <asp:QueryStringParameter Name="albumID" QueryStringField="id" Type="Int32"/> </SelectParameters> </asp:ObjectDataSource> |
下面的例子演示了一個綁定到DataSet.TableAdapter方法的ObjectDataSource。在后面幾個例子中我們將使用這個數據集演示如何使用ASP.NET數據控件實現一個簡單的相冊應用程序。請注意這個例子中的數據視圖使用了一個叫做ImageField的新字段類型來顯示照片。我們還要注意,ObjectDataSource中使用的ConvertNullToDBNull會導致空參數值在傳遞給TableAdapter方法之前被轉換為DbNull(必須的)。
| <asp:ObjectDataSource ID="ObjectDataSource1" runat="server" TypeName="DataComponentTableAdapters.AlbumsTableAdapter" SelectMethod="GetAlbumsByOwner" UpdateMethod="Update" ConvertNullToDBNull="true" OldValuesParameterFormatString="original_{0}"> </asp:ObjectDataSource> <asp:ObjectDataSource ID="ObjectDataSource2" runat="server" TypeName="DataComponentTableAdapters.OwnersTableAdapter" SelectMethod="GetOwners" /> |