ObjectDataSource 是 ASP.NET 2.0 資料繫結架構的關鍵元件,它讓 Web 表單頁面(表示層)能直接繫結至任意 .NET 類別(業務邏輯層 BLL 或資料存取層 DAL),而不限於資料庫連線。這完美支援分層架構,實現關注點分離:
| 屬性 | 說明 | 對應傳統 SqlDataSource |
|---|---|---|
| TypeName | 要實例化的類別完整名稱(含命名空間) | ConnectionString |
| SelectMethod | 查詢資料的方法名稱 | SelectCommand |
| InsertMethod | 新增資料的方法名稱 | InsertCommand |
| UpdateMethod | 更新資料的方法名稱 | UpdateCommand |
| DeleteMethod | 刪除資料的方法名稱 | DeleteCommand |
| DataObjectTypeName | 強型別資料物件的型別名稱(選用) | 無 |
public class ProductDAL
{
private string _connStr = ConfigurationManager.ConnectionStrings["Northwind"].ConnectionString;
public DataTable GetAllProducts()
{
using (SqlConnection conn = new SqlConnection(_connStr))
using (SqlCommand cmd = new SqlCommand("SELECT ProductID, ProductName, UnitPrice, Discontinued FROM Products", conn))
using (SqlDataAdapter da = new SqlDataAdapter(cmd))
{
DataTable dt = new DataTable();
da.Fill(dt);
return dt;
}
}
public int InsertProduct(string productName, decimal unitPrice, bool discontinued)
{
using (SqlConnection conn = new SqlConnection(_connStr))
using (SqlCommand cmd = new SqlCommand("INSERT INTO Products (ProductName, UnitPrice, Discontinued) VALUES (@Name, @Price, @Disc); SELECT SCOPE_IDENTITY();", conn))
{
cmd.Parameters.AddWithValue("@Name", productName);
cmd.Parameters.AddWithValue("@Price", unitPrice);
cmd.Parameters.AddWithValue("@Disc", discontinued);
conn.Open();
return Convert.ToInt32(cmd.ExecuteScalar());
}
}
// UpdateProduct, DeleteProduct 類似...
}
public class ProductBLL
{
private ProductDAL _dal = new ProductDAL();
public DataTable GetProducts() { return _dal.GetAllProducts(); }
public int AddProduct(string productName, decimal unitPrice, bool discontinued)
{
// 業務規則:產品名稱不可重複、單價必須 > 0
if (string.IsNullOrWhiteSpace(productName)) throw new ArgumentException("產品名稱必填");
if (unitPrice <= 0) throw new ArgumentException("單價必須大於零");
// 可在此檢查重複、記錄稽核日誌、發送通知等
return _dal.InsertProduct(productName, unitPrice, discontinued);
}
// UpdateProduct, DeleteProduct 類似...
}
<asp:ObjectDataSource ID="odsProducts" runat="server"
TypeName="ProductBLL"
SelectMethod="GetProducts"
InsertMethod="AddProduct"
UpdateMethod="UpdateProduct"
DeleteMethod="DeleteProduct"
DataObjectTypeName="ProductEntity" > <!-- 選用:啟用強型別參數繫結 -->
<InsertParameters>
<asp:Parameter Name="productName" Type="String" />
<asp:Parameter Name="unitPrice" Type="Decimal" />
<asp:Parameter Name="discontinued" Type="Boolean" />
</InsertParameters>
</asp:ObjectDataSource>
<asp:GridView ID="gvProducts" runat="server" DataSourceID="odsProducts" AutoGenerateColumns="False" DataKeyNames="ProductID">
<Columns>
<asp:BoundField DataField="ProductName" HeaderText="產品名稱" />
<asp:BoundField DataField="UnitPrice" HeaderText="單價" DataFormatString="{0:C}" />
<asp:CheckBoxField DataField="Discontinued" HeaderText="停售" />
<asp:CommandField ShowEditButton="True" ShowDeleteButton="True" />
</Columns>
</asp:GridView>
設定 DataObjectTypeName 指向實體類別(如 ProductEntity),ObjectDataSource 會自動將表單欄位繫結為該型別實例,傳遞給 BLL 方法,免去逐一宣告 InsertParameters。
處理 ObjectCreating 事件,手動建立 BLL 實例(如注入相依性、設定連線字串):
protected void odsProducts_ObjectCreating(object sender, ObjectDataSourceEventArgs e)
{
e.ObjectInstance = new ProductBLL(new ProductDAL("CustomConnStr"));
}
startRowIndex、maximumRows、sortExpression 參數,ObjectDataSource 自動傳值。ROW_NUMBER() OVER (ORDER BY ...) 或 OFFSET/FETCH 實作資料庫端分頁,避免撈回全量資料。處理 Inserted、Updated、Deleted 事件,檢查 e.Exception,設定 e.ExceptionHandled = true 並顯示友善訊息:
protected void odsProducts_Inserted(object sender, ObjectDataSourceStatusEventArgs e)
{
if (e.Exception != null)
{
lblError.Text = "新增失敗:" + e.Exception.InnerException.Message;
e.ExceptionHandled = true;
}
}
| 場景 | 推薦 | 理由 |
|---|---|---|
| 快速原型、簡單 CRUD、無業務邏輯 | SqlDataSource | 宣告式、零程式碼、開發最快 |
| 企業級應用、複雜業務規則、單元測試需求、多資料來源 | ObjectDataSource + BLL/DAL | 關注點分離、可測試、可維護、可擴充 |
| 既有 DAL/BLL 組件、遷移專案 | ObjectDataSource | 直接繫結現有類別,無需重寫資料存取 |
ObjectDataSource 是 ASP.NET 2.0 邁向專業分層架構的基石。善用它將資料操作封裝於 BLL/DAL,不僅符合軟體工程最佳實務,更能發揮 Visual Studio 設計器的生產力優勢(智慧標籤、參數自動產生)。掌握 TypeName/SelectMethod 等核心屬性、強型別繫結、自訂物件建立、分頁排序最佳化與例外處理,即可打造健壯、可維護的資料驅動 Web 應用。