Что определяет, что оператор Where в Linq может анализировать? - PullRequest
0 голосов
/ 16 ноября 2018

В предложении 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 Ответ

0 голосов
/ 16 ноября 2018

Ваш фильтр просто неправильного типа, который будет применен в первом примере. Синий синтаксис linq делает много магии для того, чтобы этот запрос был легко читаемым. То, что на самом деле происходит под капотом, - это создание некоторых анонимных типов, которые содержат ссылки на ваши элементы. Обратите внимание, что в предложении where вы также можете использовать переменные 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, вы можете применить свой фильтр.

...