Reputation: 439
i want to combine some Linq Expression, so i help from below articles:
http://www.c-sharpcorner.com/uploadfile/04fe4a/predicate-combinators-in-linq/ and http://thanhhh.blogspot.com/2011/10/linq-to-entities-predicatebuilder-and.html
and i have a generic list like this:
List<long> lstPA = new List<long>() { 2, 3 }; // the numbers can be added or removed
if i use under code for combine my linq expression, i get correct results(records) from db (i use Entity Framework 4.0):
var exp1 = Predicate.FalseExpression<posts>();
exp1 = exp1.Or(x => x.post_author == 2);
exp1 = exp1.Or(x => x.post_author == 3);
but when i combine linq expression in a foreach loop Like this:
var exp1 = Predicate.FalseExpression<posts>();
foreach (long id in lstPA)
{
exp1 = exp1.Or(x => x.post_author == id);
}
i can't get correct result(records) from db.
what is diffrence between 2 code blocks and how can solve this problem (i must use foreach loop)?
Upvotes: 1
Views: 1108
Reputation: 151
this appears to me to be an issue with closures and loops. Id references the loop variable and will continue to do so, which means it changes and reads something like
exp1 = exp1.Or(x => x.post_author == 3);
exp1 = exp1.Or(x => x.post_author == 3);
when unfolded. To fix that you could try:
var exp1 = Predicate.FalseExpression<posts>();
foreach (long id in lstPA)
{
long tempID = id;
exp1 = exp1.Or(x => x.post_author == tempID);
}
this makes sure a temporary variable that was created in the loop and never changed afterwards gets used instead of the loop variable which is mutated during its course.
Upvotes: 1
Reputation: 18474
I believe your issue is to do with closure. The variable id is assigned to the expression and it updates to a newer value each time you loop. In order to use it you want to make an individually scoped variable.
var exp1 = Predicate.FalseExpression<posts>();
foreach (long i in lstPA)
{
long id = i;
exp1 = exp1.Or(x => x.post_author == id);
}
However you could just use the contains clause instead in this instance.
expr1 = x => lstPA.Contains(x.post_author);
Upvotes: 7
Reputation: 171178
Looks like an instance of the foreach closure problem. You are passing two times the same ID to the database. Apply the fix described in the linked question: Copy id
to a variable inside of the loop.
Upvotes: 2