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);
}
это гарантирует, что временная переменная, которая была создана в цикле и никогда не изменялась впоследствии, будет использоваться вместо переменной цикла, которая изменяется во время ее работы.