首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> 關於.NET

基於 NBear v1.6 的領域模型層設計實戰:從實體生成到業務封裝

     編輯:關於.NET

為什麼需要獨立的領域模型層?

在 NBear 快速開發框架早期範例中,業務邏輯常直接分散於 Service 或 Facade 層,僅透過強類型實體介面操作資料。隨著業務複雜度提升,這種「貧血模型」導致領域知識外洩、重複程式碼激增、單元測試困難。NBear v1.6 引入 NBear.Domain 命名空間,提供 DomainModel 與 GuidKeyDomainModel 兩大基類,讓開發者能以最小成本建立「充血模型」,將實體屬性存取、關聯導航、驗證邏輯、事務控制封裝於領域類別內部,實現關注點分離。

核心基類架構剖析

DomainModel<IEntityType, IEntityViewType, DomainType> 實作 IDomainModel 介面,內建三大能力:

  • 狀態追蹤:雙實體欄位 entityValue(目前值)與 entityValue2(原始值)配合 Gateway.CompareEntities 實現「僅更新修改欄位」的精準 SQL 生成。
  • 完整 CRUD:Save() 自動判斷新增/更新,Find/FindAll/Delete 靜態方法支援鍵值與排序查詢,LoadFromEntity 負責 View 實體到 Domain 實體的雙向轉換。
  • 事務支援:所有寫入方法提供 DbTransaction 多載,配合 Gateway.BeginTransaction/Commit/Rollback 實現跨實體原子操作。

GuidKeyDomainModel 覆寫 DoCreate,以 Guid.NewGuid() 產生主鍵,適合分散式系統或合併複製場景。

實戰範例:從資料庫到領域模型的完整流程

1. 實體介面生成

使用 NBear.Tools.EntityGen 對範例資料庫 TestRelation.mdb 產生 Entities.cs,定義 Group、Message、User、UserGroup 等實體與對應 View 介面(vGroup、vMessage、vUser),View 介面包含關聯欄位(如 UserID)以利單表查詢。

2. 領域類別定義與擴充

public class Group : DomainModel<Entities.Group, Entities.vGroup, Group> {
    private OneToMany<...> groupToUsers;
    public override void LoadFromEntity(Entities.vGroup view) {
        base.LoadFromEntity(view);
        groupToUsers = new OneToMany<...>(Gateway.Db, "GroupID", entityValue, view);
    }
    public User[] FindUsersInGroup(string orderBy) => 
        groupToUsers == null ? null : User.EntityViewArrayToDomainArray(groupToUsers.SelectMany(null, orderBy));
    public void AddUserToGroup(object userID) { /* ... */ }
    public void DeleteUserFromGroup(object userID) { /* ... */ }
}

OneToMany 封裝關聯實體(UserGroup)的查詢、新增、刪除,業務層僅需呼叫 AddUserToGroup 即可完成中間表維護,完全隱藏 SQL 細節。

3. 應用層使用範例

GatewayManager.DefaultGateway = new Gateway(DatabaseType.MsAccess, connStr);
var group = Group.Find(1);
var users = group.FindUsersInGroup("ID desc");
group.EntityValue.Description = "modified";
group.Save();  // 僅產生 UPDATE Description WHERE ID=1

using (var tran = User.Gateway.BeginTransaction()) {
    try {
        user.EntityValue.Salary = 99999; user.Save(tran);
        var msg = new Message { EntityValue = { Title="new msg", Content="salary changed", FromUserID=user.ID, ToUserID=3, SendTime=DateTime.Now } };
        msg.Save(tran);
        tran.Commit();
    } catch { tran.Rollback(); throw; }
    finally { User.Gateway.CloseTransaction(tran); }
}

程式碼清晰展現「領域模型封裝業務規則、應用層協調事務邊界」的分層優勢。

最佳實踐建議

  • 領域類別專注單一實體生命週期與不變條件,跨聚合根操作放入 Application Service。
  • 善用 EntityViewValue 存取 View 專屬欄位(如 vUser.GroupID),避免額外 Join 查詢。
  • 大量資料匯入時可直接使用 Gateway.BulkInsert 繞過領域層,效能優先。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved