NBear ORM 框架雖提供強類型實體與查詢語法,但缺乏原生支援 GridView、DetailsView、Repeater 等標準資料繫結控件的 DataSourceControl 實作。NBearDataSource 繼承 DataSourceControl,實作 IDataSource,讓開發者在零後台程式碼情況下完成實體的完整 CRUD、排序、分頁與強類型動態查詢。
| 成員 | 類型 | 說明 |
|---|---|---|
ConnectionStringName | string | Web.config <connectionStrings> 名稱;不指定則取最後一組 |
TypeName | string | 實體完整型別名(必填),如 Entities.SimpleData |
FilterExpression | string | 靜態 WHERE 子句,{PropertyName} 對應實體屬性,如 {SimpleID} > 0 |
DefaultOrderByExpression | string | 靜態 ORDER BY,如 {SimpleID} DESC, {SimpleName} |
Filter(WhereClip) | 方法 | 運行時以強類型 WhereClip 覆蓋 FilterExpression |
OrderBy(OrderByClip) | 方法 | 運行時以強類型 OrderByClip 覆蓋 DefaultOrderByExpression |
Saving/Saved | 事件 | Insert/Update 前後攔截,e.Entity 可修改實體屬性 |
<%@ Register TagPrefix="nb" Namespace="NBear.Web.Data" Assembly="NBear.Web.Data" %>
<nb:NBearDataSource ID="TestDS" runat="server"
ConnectionStringName="test access db"
TypeName="Entities.SimpleData"
FilterExpression="{SimpleID} > 0"
DefaultOrderByExpression="{SimpleID} DESC, {SimpleName}" />
<asp:GridView ID="TestGrid" runat="server" DataSourceID="TestDS"
AllowSorting="true" AllowPaging="true" PageSize="3"
AutoGenerateEditButton="true" AutoGenerateDeleteButton="true" />
<asp:DetailsView ID="TestDetail" runat="server" DataSourceID="TestDS"
DefaultMode="Insert" AutoGenerateInsertButton="true" AutoGenerateRows="false">
<Fields><asp:BoundField DataField="SimpleName" HeaderText="Name" /></Fields>
</asp:DetailsView>
GridView 自動處理分頁/排序/編輯/刪除;DetailsView 固定插入模式,僅顯示 SimpleName 欄位。web.config 需註冊 entityConfig 區段並包含 EntityConfig.xml。
前端:TextBox (名稱模糊查詢) + 兩個 DropDownList (排序欄位/升降冪) + Button。
後端 btnFind_Click:
string name = txtName.Text.Replace("*", "%");
if (!string.IsNullOrEmpty(name))
TestDS.Filter(Entities.SimpleData._.SimpleName.Like(name)); // 強類型 WhereClip
if (listOrderByProperty.SelectedValue == "SimpleId")
TestDS.OrderBy(listOrderByDesc.SelectedIndex == 0
? Entities.SimpleData._.SimpleId.Asc
: Entities.SimpleData._.SimpleId.Desc);
else
TestDS.OrderBy(listOrderByDesc.SelectedIndex == 0
? Entities.SimpleData._.SimpleName.Asc
: Entities.SimpleData._.SimpleName.Desc);
Entities.SimpleData._ 為 NBear 產生的靜態查詢入口,Like/Asc/Desc 皆為強類型擴充方法,編譯期即可檢查拼字錯誤。
標準 Repeater 無分頁屬性,Toolkit 提供 PagableRepeater 擴充 PageIndex/PageSize:
<nb:NBearDataSource ID="TestDS" runat="server" ConnectionStringName="test access db"
TypeName="Entities.SimpleData" DefaultOrderByExpression="{SimpleID} DESC" />
<nb:PagableRepeater ID="rpPagable" runat="server" PageIndex="2" PageSize="3" DataSourceID="TestDS">
<ItemTemplate>
SimpleId=<%# Eval("SimpleId") %>, SimpleName=<%# Eval("SimpleName") %><br/>
</ItemTemplate>
</nb:PagableRepeater>
內部實作:若指定分頁參數則呼叫 Gateway.GetPageSelector().FindPage() 執行資料庫端分頁(TOP/NEXT 或 ROW_NUMBER);否則 Gateway.FindArray() 取全量。同樣支援 SqlDataSource 等任何實作 IDataSource 且支援 SelectArguments 的資料源。
頁面配置兩組 DataSource+GridView+DetailsView:
<nb:NBearDataSource ID="dsMaster" TypeName="Entities.Master" ... />
<asp:GridView ID="gdMaster" DataSourceID="dsMaster" OnSelectedIndexChanged="gdMaster_SelectedIndexChanged" ... />
<nb:NBearDataSource ID="dsDetails" TypeName="Entities.Detail" ... />
<asp:GridView ID="gdDetail" DataSourceID="dsDetails" ... />
<asp:DetailsView ID="dtDetail" DataSourceID="dsDetails" DefaultMode="Insert" ... />
後台邏輯:
protected void Page_Load(object sender, EventArgs e) {
dsDetails.Saving += dsDetails_Saving;
}
void dsDetails_Saving(object sender, NBearDataSourceEventArgs e) {
var detail = (Entities.Detail)e.Entity;
if (!detail.IsAttached()) // 新增時 IsAttached=false
detail.MasterID = int.Parse(gdMaster.SelectedRow.Cells[1].Text); // 寫入外鍵
}
protected void gdMaster_SelectedIndexChanged(object sender, EventArgs e) {
if (gdMaster.SelectedRow != null) {
gdDetail.Visible = dtDetail.Visible = true;
dsDetails.Filter(Entities.Detail._.MasterID == int.Parse(gdMaster.SelectedRow.Cells[1].Text));
} else {
gdDetail.Visible = dtDetail.Visible = false;
}
}
關鍵點:
1. Saving 事件區分新增/更新(IsAttached()),新增時自動帶入 MasterID。
2. Master GridView 選列變更時,動態設定 Detail DataSource 的 Filter 並顯示/隱藏從表區塊。
3. 刪除 Master 時需手動級聯刪除 Detail(或資料庫 FK Cascade),NBearDataSource 不自動處理跨實體級聯。
SelectedIndexChanged 設定 grid.PageSize 並 grid.DataBind()。Timestamp 或 Version 欄位,NBearDataSource 更新時自動攜帶 Where 條件防止覆蓋衝突。Gateway.Delete<T>(keys)。Saving 事件中執行實體層級驗證,失敗設定 e.Cancel = true 並顯示錯誤訊息。NBear.Web.Data.dll,需隨應用程式部署。EntityConfig.xml 結構變更與強類型查詢 API 相容性。EntityFrameworkCore + TagHelper 或 Blazor 元件,NBearDataSource 僅支援傳統 WebForms。