摘要:ADO.NET 和
SqlDataSource 使得人們可以很容易地訪問 ASP.NET 2.0 中的兩層數(shù)據(jù)。但是,它們在 n 層應(yīng)用程序中就不是那么有效了,而
ObjectDataSource 卻能在 n 層應(yīng)用程序中為業(yè)務(wù)對象提供相同的易用性。學(xué)習(xí)如何使用 ASP.NET 2.0 Framework 并利用
ObjectDataSource 控件生成嚴(yán)格意義上的多層 Web 應(yīng)用程序。
簡介
在 Microsoft ASP.NET 2.0 Framework 中,數(shù)據(jù)庫訪問得到了極大的簡化。利用全新的 SqlDataSource 控件,您無需編寫一行代碼就可以選擇、更新、插入和刪除數(shù)據(jù)庫數(shù)據(jù)。
生成簡單的應(yīng)用程序時,SqlDataSource 控件是一個很好的選擇。如果您需要迅速生成一個使用戶可以顯示和編輯數(shù)據(jù)庫記錄的 Web 頁,使用 SqlDataSource 控件在幾分鐘之內(nèi)就能完成此工作。
例如,我自己就曾計(jì)時生成了這么一個頁面。通過結(jié)合使用 SqlDataSource 控件與 GridView 控件,我在 1 分 15秒 內(nèi)就能生成一個用于顯示 Northwind Products 數(shù)據(jù)庫表的內(nèi)容的頁面。就有這么快!
但是,SqlDataSource 控件存在一個問題。如果您使用 SqlDataSource 控件,那您就是在做不太妙的事情。SqlDataSource 控件的缺點(diǎn)在于它迫使您將用戶界面層與業(yè)務(wù)邏輯層混合在一起。任何應(yīng)用程序架構(gòu)師都會告訴您:混合多個層的行為是不可取的。
生成嚴(yán)格意義上的多層 Web 應(yīng)用程序時,您應(yīng)該具有清晰的用戶界面層、業(yè)務(wù)邏輯層和數(shù)據(jù)訪問層。僅僅由于 SqlDataSource 控件的強(qiáng)制而在用戶界面層引用 SQL 語句或存儲過程是完全錯誤的。
那么為什么您要關(guān)心這些東西呢?不錯,在很多情況下,您不必在意。如果您正在創(chuàng)建一個簡單的 Web 應(yīng)用程序,完全可以使用 SqlDataSource 控件。例如,如果您需要生成一個由單獨(dú)頁面組成的應(yīng)用程序來顯示數(shù)據(jù)庫的表的內(nèi)容,那么將應(yīng)用程序劃分為多個應(yīng)用程序?qū)泳秃懿幻髦恰?/p>
遺憾的是(如果您已經(jīng)為此“交過學(xué)費(fèi)”,則會感到幸運(yùn)),并非所有的 Web 應(yīng)用程序都很簡單。應(yīng)用程序達(dá)到一定的復(fù)雜程度之后,如果將其劃分為多個應(yīng)用程序?qū)?,則生成和維護(hù)它們就更輕松。
將應(yīng)用程序劃分為多個應(yīng)用程序?qū)佑泻芏鄡?yōu)點(diǎn)。如果您有一個清晰的業(yè)務(wù)邏輯層,就能夠創(chuàng)建一個可以從多個頁面調(diào)用的方法庫。換句話說,創(chuàng)建一個清晰的業(yè)務(wù)邏輯層提升了代碼重用。此外,創(chuàng)建清晰而獨(dú)立的應(yīng)用程序?qū)邮沟脩?yīng)用程序更易于修改。例如,清晰的層次使您無需修改數(shù)據(jù)訪問代碼就可以修改用戶界面。
如果您需要使用 ASP.NET Framework 生成多層 Web 應(yīng)用程序,那么您可以使用 ASP.NET 2.0 Framework 所引入的另一個新控件:ObjectDataSource 控件ObjectDataSource 控件使您可將諸如 GridView 和 DropDownList 這樣的用戶界面控件綁定到一個中間層組件。
這篇文章的主題就是 ObjectDataSource 控件。在這篇文章中,您將學(xué)習(xí)如何使用此控件來顯示和編輯數(shù)據(jù)庫數(shù)據(jù)。我們還將討論如何結(jié)合使用 ObjectDataSource 控件和 SqlDataSource 控件以簡化數(shù)據(jù)庫訪問。
使用 ObjectDataSource 控件編輯數(shù)據(jù)
ObjectDataSource 控件包含 4 個重要屬性:SelectMethod 屬性、UpdateMethod 屬性、InsertMethod 屬性和 DeleteMethod 屬性。綜合利用這些屬性,您能夠指定執(zhí)行標(biāo)準(zhǔn)數(shù)據(jù)庫操作所需的所有方法。
例子:
綁定到數(shù)據(jù)訪問層
數(shù)據(jù)訪問層組件封裝 ADO.NET 代碼以通過 SQL 命令查詢和修改數(shù)據(jù)庫。它通常提煉創(chuàng)建 ADO.NET 連接和命令的詳細(xì)信息,并通過可使用適當(dāng)?shù)膮?shù)調(diào)用的方法公開這些詳細(xì)信息。典型的數(shù)據(jù)訪問層組件可按如下方式公開:
public class MyDataBllLayer {
public DataView GetRecords();
public int UpdateRecord(int recordID, String recordData);
public int DeleteRecord(int recordID);
public int InsertRecord(int recordID, String recordData);
}
通常是在業(yè)務(wù)邏輯訪問層定義對數(shù)據(jù)庫里記錄的操作,上面就定義了GetRecords、UpdateRecord、DeleteRecord和InsertRecord四個方法來讀取、更新、刪除和插入數(shù)據(jù)庫里的數(shù)據(jù),這些方法基本上是根據(jù)SQL里的Select、Update、Delete和Insert語句而定義。
和上面方法相對應(yīng), ObjectDataSource提供了四個屬性來設(shè)置該控件引用的數(shù)據(jù)處理,可以按照如下方式關(guān)聯(lián)到該類型,代碼如下
<asp:ObjectDataSource TypeName="MyDataLayer" runat="server"
SelectMethod="GetRecords"
UpdateMethod="UpdateRecord"
DeleteMethod="DeleteRecord"
InsertMethod="InsertRecord"
/>
這里的SelectMethon設(shè)置為MyDataBllLayer里的GetRecords()方法,在使用時需要注意ObjectDataSource旨在以聲明的方式簡化數(shù)據(jù)的開發(fā),所以這里設(shè)置SelectMethod的值為GetRecords而不是GetRecords()。
同樣依次類推,UpdateMethod/DeleteMethod/InsertMethod分別對應(yīng)的是UpdateRecord
/DeleteRecord/InsertRecord方法。
在上面GetRecords()的定義時,可以看到該方法返回的類型是DataView,由于ObjectDataSource將來需要作為綁定控件的數(shù)據(jù)來源,所以它的返回類型必須如下的返回類型之一:
Ienumerable、DataTable、DataView、DataSet或者Object。
除此以外,ObjectDataSource還有一個重要的屬性TypeName,ObjectDataSource控件使用反射技術(shù)來從來從業(yè)務(wù)邏輯程序?qū)拥念悓ο笳{(diào)用相應(yīng)的方法,所以TypeName的屬性值就是用來標(biāo)識該控件工作時使用的類名稱,下面的例子演示了ObjectDataSource的基本使用。
在該例子里定義了一個數(shù)據(jù)業(yè)務(wù)邏輯層來處理數(shù)據(jù)庫鏈接和業(yè)務(wù)邏輯,這些處理都是有App_Code文件夾下的NorthwndDB.cs文件完成,先大致瀏覽一下該文件里定義的方法:
using System;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;
using System.Collections.Generic;
using System.Web.UI;
using System.Web.UI.WebControls;
public class EmployeeInfo
{
private string _connectionString;
public EmployeeInfo()
{ _connectionString =
ConfigurationManager.ConnectionStrings["Northwind"].ConnectionString;
}
public SqlDataReader GetEmployees()
{
SqlConnection con = new SqlConnection(_connectionString);
string selectString = "SELECT EmployeeID,LastName,Firstname,Title,Address,City,Region,PostalCode FROM Employees ORDER BY EmployeeID";
SqlCommand cmd = new SqlCommand(selectString, con);
con.Open();
SqlDataReader dtr =
cmd.ExecuteReader(CommandBehavior.CloseConnection);
return dtr;
}
public void UpdateEmployee(int EmployeeId, string LastName, string Firstname, string Title, string Address, string City, String Region, string PostalCode)
{
SqlConnection con = new SqlConnection(_connectionString);
string updateString = "UPDATE Employees SET Address=@Address,City=@City WHERE EmployeeID=@EmployeeID";
SqlCommand cmd = new SqlCommand(updateString, con);
cmd.Parameters.AddWithValue("@Address", Address);
cmd.Parameters.AddWithValue("@City", City);
cmd.Parameters.AddWithValue("@EmployeeID", EmployeeId);
con.Open();
cmd.ExecuteNonQuery();
con.Close();
}
public void DeleteEmployee(int EmployeeId)
{
SqlConnection con = new SqlConnection(_connectionString);
string deleteString = "DELETE Employees WHERE EmployeeID=@EmployeeID";
SqlCommand cmd = new SqlCommand(deleteString, con);
cmd.Parameters.AddWithValue("@EmployeeId", EmployeeId);
con.Open();
cmd.ExecuteNonQuery();
con.Close();
}
}
在這段代碼里,定義了GetEmployees方法來獲取所有員工級別信息,UpdateEmployee方法更新員工的基本資料,DeleteEmployee方法用來刪除員工資料,這樣就可以在ObjectDataSource1.aspx里使用如下代碼調(diào)用業(yè)務(wù)邏輯的處理,如下
<asp:GridView
ID="GridView1"
DataSourceID="ObjectDataSource1"
DataKeyNames="EmployeeId"
AutoGenerateColumns="true"
AutoGenerateEditButton="True"
AutoGenerateDeleteButton="True"
Runat="Server" CellPadding="4" Font-Names="Verdana" Font-Size="X-Small" ForeColor="#333333" GridLines="None">
… …
</asp:GridView>
<asp:ObjectDataSource
ID="ObjectDataSource1"
TypeName="EmployeeInfo"
SelectMethod="GetEmployees"
UpdateMethod="UpdateEmployee"
DeleteMethod="DeleteEmployee"
Runat="Server">
<UpdateParameters>
<asp:Parameter Name="EmployeeId" Type="Int32" />
<asp:Parameter Name="Address" />
<asp:Parameter Name="City" />
</UpdateParameters>
</asp:ObjectDataSource>
上面使用了GrieView控件后面會有專門介紹,這里我們專注ObjectDataSource控件的使用,在該控件里設(shè)置 TypeName為"EmployeeInfo"表示將來調(diào)用的類名稱為EmployeeInfo,調(diào)用SelectMethond/UpdateMethod/DeleteMethod調(diào)用的的方法分別是EmployeeInfo類里的GetEmployees/UpdateEmployee/DeleteEmployee方法。
具體運(yùn)行可以自己試驗(yàn)。從運(yùn)行結(jié)果里單擊“Edit”可以更新員工的資料,單擊“Delete”將刪除員工的資料。
在運(yùn)行上面的例子里,可能看到UpdateEmployee的定義如下:
public void UpdateEmployee(int EmployeeId, string LastName, string Firstname, string Title, string Address, string City, String Region, string PostalCode)
{ ... ...
cmd.Parameters.AddWithValue("@Address", Address);
cmd.Parameters.AddWithValue("@City", City);
cmd.Parameters.AddWithValue("@EmployeeID", EmployeeId);
... ...
}
這段代碼表示更新員工資料時,其實(shí)只更新了員工的地址(Address)和所在的程序(City),而對于姓名(FirstName,LastName)、職稱(Title)等并沒有更新。
既然FistName、LastName、Title等并沒有更新,為什么不將UpdateEmployee寫成如下方式呢?
public void UpdateEmployee(int EmployeeId string Address, string City,)
{ ... ...
cmd.Parameters.AddWithValue("@Address", Address);
cmd.Parameters.AddWithValue("@City", City);
cmd.Parameters.AddWithValue("@EmployeeID", EmployeeId);
... ...
}
也就是只保留需要的三個參數(shù)而將其它變量不寫,如果這樣做將發(fā)生錯誤如下:
提示錯誤為:ObjectDataSource1找不到一個包含Address,City,LastName,F(xiàn)irstname,Title,Region,PostalCode和Employee參數(shù)的非泛型方法(具體原因我還沒有進(jìn)行驗(yàn)證,我的感覺是ObjectDataSource是根據(jù)Select語句自動生成Delete/Insert/Update等的,所以在更新時,同樣需要該參數(shù),你可以到如下MSDN查看SelectMethod的說明:
http://msdn2.microsoft.com/en-us/library/system.web.ui.webcontrols.objectdatasource.selectmethod(VS.80).aspx
)。
而我看到的例子,大多都是如下寫法:
public void UpdateEmployee(int EmployeeId, string LastName, string Firstname, string Title, string Address, string City, String Region, string PostalCode)
{
UpdateEmployee(EmployeeId,Address,City)
}
public void UpdateEmployee(int EmployeeId, string Address, string City )
{
SqlConnection con = new SqlConnection(_connectionString);
string updateString = "UPDATE Employees SET Address=@Address,City=@City WHERE EmployeeID=@EmployeeID";
SqlCommand cmd = new SqlCommand(updateString, con);
cmd.Parameters.AddWithValue("@Address", Address);
cmd.Parameters.AddWithValue("@City", City);
cmd.Parameters.AddWithValue("@EmployeeID", EmployeeId);
con.Open();
cmd.ExecuteNonQuery();
con.Close();
}
通過重載UpdateEmployee方法,便于數(shù)據(jù)的擴(kuò)展和維護(hù)。
綁定到業(yè)務(wù)邏輯
為了更好的進(jìn)行業(yè)務(wù)處理,需要進(jìn)一步封裝業(yè)務(wù)邏輯,以便返回強(qiáng)類型,舉例定義一個Product來封裝數(shù)據(jù)庫,具體由Product.cs類來實(shí)現(xiàn)并放在App_Code目錄.
using System;
public class Product
{
protected int _productID;
protected String _productName;
protected int _categoryID;
protected decimal _price;
protected int _inStore;
protected String _description;
public int ProductID
{
get { return _productID; }
set { _productID = value; }
}
public String ProductName
{
get { return _productName; }
set { _productName = value; }
}
public int CategoryID
{
get { return _categoryID; }
set { _categoryID = value; }
}
public decimal Price
{
get { return _price; }
set { _price = value; }
}
public int InStore
{
get { return _inStore; }
set { _inStore = value; }
}
public String Description
{
get { return _description; }
set { _description = value; }
}
public Product()
{ }
public Product(int productID, string productName, int categoryID, decimal price, int instore, string description)
{
this._productID = productID;
this._productName = productName;
this._categoryID = categoryID;
this._price = price;
this._inStore = instore;
this._description = description;
}
}
然后定義業(yè)務(wù)邏輯類ProductDB.cs來進(jìn)行處理:
using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Collections.Generic;
using System.Data.SqlClient;
/// <summary>
/// ProductDB 的摘要說明
/// </summary>
public class ProductDB
{
public ProductDB()
{
//
// TODO: 在此處添加構(gòu)造函數(shù)邏輯
//
}
public List<Product> GetProduct()
{
List<Product> products = new List<Product>();
SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["MyDatabase"].ConnectionString);
string commandText = "select * from Products";
SqlCommand command = new SqlCommand(commandText,conn);
conn.Open();
SqlDataReader dr = command.ExecuteReader();
while (dr.Read())
{
Product prod = new Product();
prod.ProductID = (int)dr["ProductID"];
prod.ProductName = (string)dr["ProductName"];
prod.CategoryID = (int)dr["CategoryID"];
prod.Price = (decimal)dr["price"];
prod.InStore = (Int16)dr["InStore"];
prod.Description = (String)dr["Description"];
products.Add(prod);
}
dr.Close();
conn.Close();
return products;
}
public void UpdateProduct(Product pro)
{
SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["MyDatabase"].ConnectionString);
SqlCommand updatecmd = new SqlCommand("UPDATE Products set ProductName=@ProductName,CategoryID=@CategoryID,Price=@Price,InStore=@InStore,Description=@Description where ProductID=@ProductID", conn);
updatecmd.Parameters.Add(new SqlParameter("@ProductName", pro.ProductName));
updatecmd.Parameters.Add(new SqlParameter("CategoryID", pro.CategoryID));
updatecmd.Parameters.Add(new SqlParameter("@Price", pro.Price));
updatecmd.Parameters.Add(new SqlParameter("@InStore", pro.InStore));
updatecmd.Parameters.Add(new SqlParameter("@Description", pro.Description));
updatecmd.Parameters.Add(new SqlParameter("@ProductID", pro.ProductID));
conn.Open();
updatecmd.ExecuteNonQuery();
conn.Close();
}
public void DeleteProduct(Product pro)
{
SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["MyDatabase"].ConnectionString);
SqlCommand delcmd = new SqlCommand("delete from Products where ProductID=@ProductID", conn);
delcmd.Parameters.Add(new SqlParameter("@ProductID", pro.ProductID));
conn.Open();
delcmd.ExecuteNonQuery();
conn.Close();
}
}
最后建立前臺頁面文件,添加objectdatasource控件顯示數(shù)據(jù)
<asp:ObjectDataSource ID="ObjectDataSource1" runat="server" DataObjectTypeName="Product"
DeleteMethod="DeleteProduct" SelectMethod="GetProduct" TypeName="ProductDB" UpdateMethod="UpdateProduct">
</asp:ObjectDataSource>
<asp:GridView ID="GridView1" runat="server" AutoGenerateDeleteButton="True" AutoGenerateEditButton="True"
CellPadding="4" DataKeyNames="ProductID" DataSourceID="ObjectDataSource1" Font-Names="Verdana"
Font-Size="XX-Small" ForeColor="#333333" GridLines="None">
<FooterStyle BackColor="#1C5E55" Font-Bold="True" ForeColor="White" />
<RowStyle BackColor="#E3EAEB" />
<EditRowStyle BackColor="#7C6F57" />
<SelectedRowStyle BackColor="#C5BBAF" Font-Bold="True" ForeColor="#333333" />
<PagerStyle BackColor="#666666" ForeColor="White" HorizontalAlign="Center" />
<HeaderStyle BackColor="#1C5E55" Font-Bold="True" ForeColor="White" />
<AlternatingRowStyle BackColor="White" />
</asp:GridView>