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

LINQ 動態查詢實作:PredicateBuilder 與 Expression Tree 構建技巧

     編輯:關於.NET

動態查詢指查詢條件與值在執行期才能決定,無法硬編碼 Lambda 運算式。本文展示三種常見動態查詢場景與解決方案。

場景一:多條件 AND 組合(最簡單)

public IQueryable<Customer> GetCustomers(string city, string contactName) {
    var context = GenerateContext();
    IQueryable<Customer> result = context.Customers;
    if (!string.IsNullOrEmpty(city))
        result = result.Where(c => c.City == city);
    if (!string.IsNullOrEmpty(contactName))
        result = result.Where(c => c.ContactName.Contains(contactName));
    return result; // 鏈式 Where 即為 AND 關係
}

場景二:多值 OR 組合(Union 方案)

查詢 City 為 London 或 Paris:

string[] cities = { "London", "Paris" };
IQueryable<Customer> result = null;
foreach (string item in cities) {
    string tmp = item; // 閉包陷阱避免
    result = result == null
        ? context.Customers.Where(c => c.City == tmp)
        : result.Union(context.Customers.Where(c => c.City == tmp));
}

缺點:產生 UNION SQL,非理想的 OR 條件,效能較差。

場景三:Expression Tree 動態構建 OR 條件(最佳方案)

使用 PredicateBuilder(出自《C# 3.0 In Nutshell》)以 Lambda 語法構建運算式樹:

var context = GenerateContext();
Expression<Func<Customer, bool>> filter = PredicateBuilder.False<Customer>();
string[] cities = { "London", "Paris" };
foreach (string item in cities) {
    string tmp = item;
    filter = filter.Or(c => c.City == tmp);
}
context.Customers.Where(filter).Count().Dump();

產生理想 SQL:

SELECT COUNT(*) FROM [Customers] WHERE ([City] = @p0) OR ([City] = @p1)

核心概念釐清

術語說明
Expression<TDelegate>運算式樹節點,可被 LINQ to SQL 解析為 SQL
Func<T, bool>委托,僅能在記憶體中執行(LINQ to Objects)
PredicateBuilder輔助類別,提供 And/Or 擴充方法組合運算式

關鍵差異:

context.Customers.Where(condition);           // condition: Expression<Func<Customer,bool>> → 翻譯為 SQL
context.Customers.Where(condition.Compile()); // 編譯為 Func → 在記憶體篩選(效能差)

替代方案:Dynamic LINQ

若習慣字串拼接 SQL,可使用 ScottGu 推薦的 Dynamic LINQ Library,支援字串形式查詢條件。

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