Что определяет, что оператор Where в Linq может анализировать?
В предложении Where оператора Linq, например,
var myClasses = (from b in db.MyRecords
join p in db.People on b.PersonId equals p.PersonId
join cse in db.Courses on b.CourseId equals cse.CourseId
where (b.Active == 1)
select new { b });
Выражение b.Active==1
работает отлично. Но если я сделаю это,
Expression<Func<MyRecords, bool>> filter = my => my.Active == 1;
[Обновление: из-за ответа Ганса я сохранил это как оригинал, но на самом деле я здесь ошибся. Выражение на самом деле использует базовый тип, а не EF, сгенерированный во множественном числе, как запрос Linq. У меня действительно есть это,
Expression<Func<MyRecord, bool>> filter = my => my.Active == 1;
]
И попробуй это,
var myClasses = (from b in db.MyRecords
join p in db.People on b.PersonId equals p.PersonId
join cse in db.Courses on b.CourseId equals cse.CourseId
where (filter)
select new { b });
Компилятор жалуется,
Невозможно преобразовать выражение запроса в предполагаемый тип делегата, поскольку некоторые из возвращаемых типов в блоке неявно не преобразуются в возвращаемый тип делегата.
Я видел много ТАКОГО вопроса с этим, но я не понимаю, почему это не будет работать. Я неправильно понимаю фундаментальное значение, поэтому я никого не прошу писать код. Я хочу знать, чего хочет Linq, поэтому я лучше понимаю Linq, а не просто заставляю что-то работать. Это работает, например,
var myClasses = (from b in db.MyRecords.Where(filter)
join p in db.People on b.PersonId equals p.PersonId
join cse in db.Courses on b.CourseId equals cse.CourseId
select new { b });
Я хочу знать, почему это работает там, а не в Где после соединений. Если я сделаю Где в конце объединений, компилятор все еще будет знать о полях MyRecords, включая Active.
Я думаю, что это то, что мне нужно для правильного описания, так как оно, похоже, подходит мне, наверное, очень хорошо.
1 ответ
Ваш фильтр просто неправильного типа, который будет применен в первом примере. Синий синтаксис linq делает много магии для того, чтобы этот запрос был легко читаемым. То, что на самом деле происходит под капотом, - это создание некоторых анонимных типов, которые содержат ссылки на ваши элементы. Обратите внимание, что в этом месте, где вы можете использовать p
а также cse
переменные также. И когда вы учитываете это в своем выражении, вы можете понять, что это так Expression<Func<Tuple<MyRecords, People, Courses>>
на самом деле это будет не кортеж, а какой-то анонимный тип.
Когда вы просите resharper преобразовать синий синтаксис в цепочку методов, он генерирует его следующим образом:
(db.MyRecords.Join(
db.People,
b => b.PersonId,
p => p.PersonId,
(b, p) => new {b, p})
.Join(
db.Courses,
t => t.b.CourseId,
cse => cse.CourseId,
(t, cse) => new {t, cse})
.Where(t => (t.t.b.Active == 1))
.Select(t => new {t.t.b}));
И на самом деле вы не можете использовать переменную фильтра в синем синтаксисе, как вы это сделали:
... join cse in db.Courses on b.CourseId equals cse.CourseId
where (filter)
Вы должны были бы переключиться на вызов метода:
(from b in db.MyRecords
join p in db.People on b.PersonId equals p.PersonId
join cse in db.Courses on b.CourseId equals cse.CourseId
select b)
.Where(filter)
теперь только потому, что мы урезали внутренний запрос просто b
Вы можете применить свой фильтр.