查詢時常需根據使用者輸入動態組合 WHERE 條件。LINQ to SQL 雖強型別,但動態建構條件比拼接 SQL 字串稍顯繁瑣。本文介紹三種方法,目標皆為:從 Northwind Customers 表找出 CompanyName 包含 keywords 陣列中任一關鍵字的資料。
手動建構 Expression<Func<Customers, bool>>,最貼近 LINQ 本質,效能最佳。
public static IEnumerable<Customers> GetCustomersFunc1(string[] keywords) {
DataClassesDataContext dc = new DataClassesDataContext();
// 參數表達式:c => ...
ParameterExpression c = Expression.Parameter(typeof(Customers), "c");
// 初始條件為 false (邏輯 OR 起始值)
Expression condition = Expression.Constant(false);
foreach (string keyword in keywords) {
// c.CompanyName.Contains(keyword)
Expression con = Expression.Call(
Expression.Property(c, typeof(Customers).GetProperty("CompanyName")),
typeof(string).GetMethod("Contains", new Type[] { typeof(string) }),
Expression.Constant(keyword)
);
// 邏輯 OR 累加
condition = Expression.Or(con, condition);
// 若需 AND 則用 Expression.And,並將初始值改為 true
}
// 建立 Lambda:c => condition
Expression<Func<Customers, bool>> end = Expression.Lambda<Func<Customers, bool>>(condition, new ParameterExpression[] { c });
var result = dc.Customers.Where(end);
return result;
}
引用 Dynamic.cs (隨 LINQ Samples 提供),以字串形式撰寫條件,語法直觀。
public static IEnumerable<Customers> GetCustomersFunc2(string[] keywords) {
DataClassesDataContext dc = new DataClassesDataContext();
string queryString = "";
foreach (string keyword in keywords) {
// 產生:CompanyName.Contains("keyword1") or CompanyName.Contains("keyword2") or ...
queryString += "CompanyName.Contains(\"" + keyword + "\") or ";
}
// 避免尾端 "or" 語法錯誤,加上永假條件
queryString += "1=0";
return dc.Customers.Where(queryString);
}
本質仍是拼接 SQL,但透過 ExecuteQuery<T> 映射回實體,適合極複雜或效能敏感情境。
public static IEnumerable<Customers> GetCustomersFunc3(string[] keywords) {
DataClassesDataContext dc = new DataClassesDataContext();
string sqlQuery = "SELECT [CustomerID], [CompanyName], ... FROM [dbo].[Customers] WHERE ";
foreach (string keyword in keywords) {
sqlQuery += "([CompanyName] LIKE '%" + keyword + "%') OR ";
}
sqlQuery += "(1=0)";
return dc.ExecuteQuery<Customers>(sqlQuery);
}
| 方法 | 優點 | 缺點 | 適用情境 |
|---|---|---|---|
| 運算式樹 | 強型別、效能最好、編譯時期檢查 | 程式碼較冗長、需熟悉 Expression API | 核心查詢邏輯、高效能需求 |
| Dynamic LINQ | 語法簡潔、接近原生 LINQ、支援排序/分組字串 | 執行時期才驗證、需額外引用 Dynamic.cs | 動態報表、使用者自訂篩選 |
| 拼接 SQL | 完全控制 SQL、可用資料庫特有功能 | 失去型別安全、SQL Injection 風險、維護困難 | 極複雜查詢、舊系統遷移、效能微調 |
優先考慮運算式樹或 Dynamic LINQ,保持型別安全與可維護性。僅在必要時退而求其次使用 SQL 字串。完整範例請參考原文程式碼註解。