C# Как объединить некоторые выражения Linq в цикле

Я хочу объединить некоторые выражения Linq, поэтому я помогу из следующих статей:

http://www.c-sharpcorner.com/uploadfile/04fe4a/predicate-combinators-in-linq/ и http://thanhhh.blogspot.com/2011/10/linq-to-entities-predicatebuilder-and.html

и у меня есть общий список, как это:

List<long> lstPA = new List<long>() { 2, 3 }; // the numbers can be added or removed

если я использую под кодом для объединения моего выражения linq, я получаю правильные результаты (записи) из БД (я использую 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);

но когда я объединяю выражение linq в цикле foreach Вот так:

var exp1 = Predicate.FalseExpression<posts>();
foreach (long id in lstPA)
{
    exp1 = exp1.Or(x => x.post_author == id);
}

я не могу получить правильный результат (записи) из БД.

Что такое разница между двумя блоками кода и как можно решить эту проблему (я должен использовать цикл foreach)?

3 ответа

Решение

Я считаю, что ваша проблема связана с закрытием. Переменная id присваивается выражению, и оно обновляется до нового значения при каждом цикле. Чтобы использовать его, нужно создать переменную с индивидуальной областью действия.

var exp1 = Predicate.FalseExpression<posts>();
foreach (long i in lstPA)
{
    long id = i;
    exp1 = exp1.Or(x => x.post_author == id);
}

Однако в этом случае вы могли бы просто использовать вместо него предложение contains.

expr1 = x => lstPA.Contains(x.post_author);

Выглядит как пример проблемы закрытия foreach. Вы дважды передаете один и тот же идентификатор в базу данных. Примените исправление, описанное в связанном вопросе: Копировать id к переменной внутри цикла.

Мне кажется, это проблема с замыканиями и петлями. Id ссылается на переменную цикла и будет продолжать это делать, что означает, что она изменяется и читает что-то вроде

exp1 = exp1.Or(x => x.post_author == 3);
exp1 = exp1.Or(x => x.post_author == 3);

когда развернул. Чтобы исправить это, вы можете попробовать:

var exp1 = Predicate.FalseExpression<posts>();
foreach (long id in lstPA)
{
  long tempID = id;
  exp1 = exp1.Or(x => x.post_author == tempID);
}

это гарантирует, что временная переменная, которая была создана в цикле и никогда не изменялась впоследствии, будет использоваться вместо переменной цикла, которая изменяется во время ее работы.

Другие вопросы по тегам