Что определяет, что оператор 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.

Я думаю, что это то, что мне нужно для правильного описания, так как оно, похоже, подходит мне, наверное, очень хорошо.

http://www.albahari.com/nutshell/linqkit.aspx

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 Вы можете применить свой фильтр.

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