2017年2月23日 星期四

【C#】PredicateBuilder usage tip

動態串接 AND, OR 條件應該算是非常常見的需求,在 Linq 段我們常會用 PredicateBuilder 這個擴充來達成,但這個擴充使用上我覺得不是那麼直觀,這篇主要只是要簡單紀錄下
var predicateA = PredicateBuilder.False<YourClass>();
var predicateB = PredicateBuilder.True<YourClass>();
的差異

我每次看到這個建構模式,都會忘記 False() 或 True() 是在表達什麼,其實它們表達的是連續串接中的第一個條件式,以下程式舉例
List<Foo> coll = new List<Foo> {
 new Foo() { A = 0, B = 0 },
 new Foo() { A = 1, B = 1 },
 new Foo() { A = 1, B = 0 }
};

var predicateA = PredicateBuilder.False<Foo>();
predicateA = predicateA.Or(f => f.A == 1);
predicateA = predicateA.Or(f => f.B == 1);
var queryResultA = coll.AsQueryable().Where(predicateA);

var predicateB = PredicateBuilder.False<Foo>();
predicateB = predicateB.Or(f => f.A == 1 && f.B == 0);
predicateB = predicateB.Or(f => f.A == 0 && f.B == 1);
var queryResultB = coll.AsQueryable().Where(predicateB);

predicateA 的串接的表達是 (Fasle || A==1 || B==1),第一個 Fasle 即是來自PredicateBuilder 的 False 方法,所以
queryResultA 的結果會是 [{ A = 1, B = 1 }, { A = 1, B = 0 }]

而 predicateB 則是 (Fasle || (A==1 && B==0) || (A==0 && B==1)),所以 queryResultB 只有 [{ A = 1, B = 0 }]。

所以換言之如果你用了
var predicate = PredicateBuilder.True<YourClass>();
那不論你後面的 OR 怎麼串,因為在第一個條件必定通過的情況下,結果就都是會查回全部資料了。

沒有留言:

張貼留言