Mahdi Radi
Mahdi Radi

Reputation: 439

C# How Combine Some Linq Expression In a Loop

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

Answers (3)

Stratege
Stratege

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

Bob Vale
Bob Vale

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

usr
usr

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

Related Questions