Entity Framework не отправляет предложения Where как предложения WHERE на SQL Server - PullRequest
7 голосов
/ 11 февраля 2010

У меня есть простая БД с сайтами, и у каждого сайта есть куча сообщений.

Я пытаюсь получить все "публичные" сообщения определенного сайта (у меня есть переменная с именем site, которая уже является экземпляром, созданным EF)

Первая очевидная вещь:

  var posts = from post in site.Posts
              where post.Public == true
              orderby post.PublicationTime descending
              select post;

Это приносит мне то, что я хочу, но, глядя на SQL Server Profiler, ГДЕ фильтрует только открытое поле, а не сайт. Фактически, выполнение в SQL Server запроса, который захватывает Profiler, действительно возвращает все сообщения со всех сайтов (и это, очевидно, будет отфильтровано на стороне ASP.Net позже).

Тогда я попробовал:

  var posts = from post in db.Posts
              where post.Site == site && post.Public == true
              orderby post.PublicationTime descending
              select post;

Тот же результат.

Я делаю здесь что-то принципиально глупое?
Фильтрует ли Entity Framework ВСЕГДА на стороне клиента?

Спасибо!
Daniel

Ответы [ 2 ]

9 голосов
/ 11 февраля 2010

Вам необходимо понять разницу между LINQ to Entities и LINQ to Objects. Это невероятно важно отслеживать при работе с Entity Framework.

Когда вы отправляете запрос к ObjectContext, вы работаете в LINQ to Entities. Это вернет IQueryable. Пока вы работаете с переменной типа IQueryable, вы можете дополнительно составить запрос с помощью LINQ API, и когда вы окончательно перечислите результат, он будет преобразован в SQL.

Но вы говорите:

(у меня есть переменная site, которая уже является экземпляром, созданным EF)

Здесь вы запрашиваете свойство объекта, поэтому вы работаете в LINQ to Objects, а не в LINQ to Entities. Это означает, что ваш запрос имеет другого поставщика и не будет преобразован в SQL.

Относительно вашего второго запроса:

var posts = from post in db.Posts
            where post.Site == site && post.Public == true
            orderby post.PublicationTime descending
            select post;

EF не позволяет вам сравнивать идентичности экземпляров в L2E. Вы должны сравнить ключ вместо этого. Попробуйте:

var posts = from post in db.Posts
            where post.Site.Id == site.Id && post.Public
            orderby post.PublicationTime descending
            select post;

Кстати, я изменил post.Public == true на post.Public. Я думаю, что это чище.

4 голосов
/ 31 января 2017

На случай, если у кого-то возникнут проблемы с использованием синтаксиса метода:

Если вы передадите Func<TEntity,Boolean> методу .Where, функция фильтра будет применена после того, как запрос вернется из базы данных. Это потому, что возвращаемое значение метода .Where возвращает IEnumerable. С другой стороны, если вы передаете Expression<Func<TEntity,Boolean> методу .Where, функция фильтра генерирует предложение where, которое отправляется в базу данных. Это потому, что .Where возвращает IQueryable. Пока вы придерживаетесь IQueryables, вы создаете запрос для отправки в базу данных. Когда вы возвращаете IEnumerable, все до метода используется для создания запроса и все после IEnumerable применяется к тому, что возвращается. Это действительно имеет значение, только если вы храните свою лямбда-функцию в переменной. Если вы передадите лямбду напрямую в метод .Where, у вас, как правило, не будет проблем. Надеюсь, это поможет !!

IEnumerable Где: https://msdn.microsoft.com/en-us/library/bb549418(v=vs.110).aspx

IQueryable Где: https://msdn.microsoft.com/en-us/library/bb535040(v=vs.110).aspx

...