Nesting OR using Linq PredicateBuilder

怎甘沉沦 提交于 2019-12-06 07:59:34
foreach (var id in ids)
{
    predicate = predicate.Or(x => x.Source.Id == id);
}

You are closing over the loop variable. Make a local copy of your id variable instead:

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

Since Linq is lazy your Or predicate and hence id will only be evaluated when you execute the query and at that time the value of id is the last item in the ids collection. The behavior of foreach in this regard will be changed in C# 5 where this will not be a problem anymore. For more info read "Closing over the loop variable considered harmful"

If that's all you're doing and your list isn't long, you don't need the predicate builder at all.

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

If you are going to use the predicate builder then you need to build the OR clause completely, then AND all of it in one go. In addition, you need to use a local id variable otherwise it will close over the iteration variable and only get its last value bound.

// 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 );
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!