2012-02-07 15 views
2

を使用して、私は次のコードを書くために述語ビルダーを使用しています:SQLは(単にWHERE句)のようなルックスを生成ネストOR LINQのPredicateBuilder

IEnumerable<int> ids= new List<int> { 47, 48 }; 

var predicate = PredicateBuilder.False<Customer>(); 

predicate = predicate.And(x => x.CreatedAt >= fromDate && x.CreatedAt <= toDate); 

foreach (var id in ids) 
{ 
    predicate = predicate.Or(x => x.Source.Id == id); 
} 

var result = Database.Set<Customer>().AsExpandable() 
            .Where(predicate) 
            .ToList(); 

を:

WHERE ([Filter6].[SourceId] IN (@p__linq__0,@p__linq__1)) 
AND ([Filter6].[CreatedAt] >= @p__linq__2) 
AND ([Filter6].[CreatedAt] <= @p__linq__3)', 
N'@p__linq__0 int, 
@p__linq__1 int, 
@p__linq__2 datetime2(7), 
@p__linq__3 datetime2(7)', 
@p__linq__0=48, 
@p__linq__1=48, 
@p__linq__2='2012-02-07 21:59:55.0437985', 
@p__linq__3='2012-02-07 22:04:55.5748288' 

それは、ID 48のようになります。 SQLで2回割り当てられました。理由は分かりませんか?

答えて

6
foreach (var id in ids) 
{ 
    predicate = predicate.Or(x => x.Source.Id == id); 
} 

ループ変数をクローズしています。代わりにあなたのid変数のローカルコピーを作成します。

foreach (var id in ids) 
{ 
    int localId = id; 
    predicate = predicate.Or(x => x.Source.Id == localId); 
} 

LINQのは怠け者なので、クエリを実行すると、あなたのOr述語となりidのみが評価され、その時点でidが最後の項目でありますidsコレクションのこの点に関してforeachの動作はC#5で変更されますが、これはもはや問題にはなりません。詳細情報を読む"Closing over the loop variable considered harmful"

3

あなたがしていることが全てで、あなたのリストが長くない場合は、述語ビルダーはまったく必要ありません。

var result = Database.Set<Customer>().AsExpandable() 
             .Where(x => x.CreatedAt >= fromDate 
                && x.CreatedAt <= toDate 
                && ids.Contains(x.Source.Id)) 
             .ToList(); 

あなたは述語ビルダーを使用しようとしているなら、あなたは一度に、その後、完全にOR句を構築し、それをすべてする必要があります。さらに、ローカルid変数を使用する必要があります。それ以外の場合は、反復変数をクローズし、最後の値を取得します。

// This should translate to True AND (u AND x) AND (FALSE OR y OR z) 
var predicate = PredicateBuilder.True<Customer>(); 

predicate = predicate.And(x => x.CreatedAt >= fromDate && x.CreatedAt <= toDate);  

var idPredicate = PredicateBuilder.False<Customer>();  
foreach (var id in ids)  
{ 
    var localId = id; 
    idPredicate = idPredicate.Or(x => x.Source.Id == localId);  
} 

predicate = predicate.And(idPredicate); 
関連する問題