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

EntityFramework 領域驅動設計實踐(十):Specification 模式與 LINQ Expression 進階實作

     編輯:關於.NET

動機:倉儲介面爆炸與查詢邏輯硬編碼

傳統倉儲介面隨查詢需求增長而膨脹:

interface ICustomerRepository {
    Customer GetByName(string name);
    Customer GetByUserName(string userName);
    IList<Customer> GetAllRetired(); // 「退休」定義模糊:年齡?病退?性別?
}

缺點:擴展需修改介面與實作、語義不明確、難以測試。

Specification 模式:將斷言條件物件化

核心介面:

interface ISpecification {
    bool IsSatisfiedBy(object obj);
    Expression<Func<object, bool>> Expression { get; } // 引入 LINQ Expression
}

倉儲簡化為:

interface IRepository<TEntity> {
    TEntity GetBySpecification(ISpecification spec);
    IEnumerable<TEntity> GetAllBySpecification(ISpecification spec);
}

具體規約類別:

class NameSpecification : Specification {
    string _name;
    public NameSpecification(string name) { _name = name; }
    public override Expression<Func<object, bool>> Expression 
        => o => ((Customer)o).FirstName == _name;
}
class RetiredSpecification : Specification {
    public override Expression<Func<object, bool>> Expression 
        => o => ((Customer)o).Age >= 60;
}

用法:repo.GetAllBySpecification(new RetiredSpecification())。解耦倉儲與查詢條件,條件可組合、可測試、可擴展。

組合規約與表達式樹優勢

  • And/Or/Not 組合規約,形成規約樹。
  • Expression 屬性:將規約轉為 Expression<Func<T, bool>>,直接傳遞給 EF/NHibernate/Db4o 的 LINQ Provider,在資料庫端過濾,避免全表掃描。
  • Eval 靜態工廠:Specification.Eval(o => (o as Customer).UserName == "daxnet"),無需建立類別即可即時建構規約。

跨持久化技術的解析器模式

定義 ISpecificationParser<TResult>,針對 NHibernate 實現 NHibernateSpecificationParser 將規約轉為 ICriteria;EF 則直接使用 Expression,無需額外解析器。

類別圖總覽

Specification 類別圖

結語

Specification + LINQ Expression 實現了:查詢語義明確化、倉儲介面穩定化、跨 ORM 可移植、效能下推資料庫。歡迎討論更多實踐細節。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved