Производительность платформы сущностей при использовании методов в предложении select - PullRequest
0 голосов
/ 19 октября 2011

Я смотрю на SQL, сгенерированный при выполнении простых запросов на выборку. Сначала я использую код с примером контекста блога от nuget.

Если выполняется следующее:

BlogContext _context = new BlogContext();
var comments = _context.Comments.Select(c => new CommentReadOnly {Author = c.Author});
var count = comments.Count();

Создается следующий SQL:

SELECT 
  [GroupBy1].[A1] AS [C1]
FROM ( SELECT 
    COUNT(1) AS [A1]
    FROM [dbo].[Comments] AS [Extent1]
)  AS [GroupBy1] 

Где подсчет выполняется в ожидаемом SQL.

Однако, если я изменю код, чтобы он выглядел так:

BlogContext _context = new BlogContext();
var comments = _context.Comments.Select(c => new CommentReadOnly {Author = c.Author});
var count = comments.Count();

private CommentReadOnly ToCommentReadOnly(Comment comment)
{
  return new CommentReadOnly
  {
    Author = comment.Author,
  };
}

Создается следующий SQL:

SELECT 
 [Extent1].[ID] AS [ID], 
 [Extent1].[PostID] AS [PostID], 
 [Extent1].[Text] AS [Text], 
 [Extent1].[Author] AS [Author]
FROM [dbo].[Comments] AS [Extent1]  

С кодом count, выполненным в коде.

Причина (я думаю) в том, что первое возвращается как IQueryable, где вторым является IEnumerable.

Можно ли вернуть второй запрос как IQueryable без выполнения SQL?

Причина, по которой я спрашиваю, заключается в том, что я создаю общий слой репозитория, который может запрашивать мои сущности и преобразовывать их в требуемый тип (в приведенном выше примере комментарий может содержать несколько разных «только для чтения» объектов). Я не хочу, чтобы SQL выполнялся так рано, поскольку может выполняться подкачка страниц или другая фильтрация в других ситуациях.

Ответы [ 2 ]

0 голосов
/ 19 октября 2011

Я думаю, что во втором запросе вы выполняете функцию ToCommentReadOnly (), так что это не может быть сделано полностью в SQL, и вы получаете Linq To Objects (IEnumerable).

Но вы заявляете, что хотите вернуть IQueryable из вашего репозитория. Это не рекомендуемая практика! Код для доступа к данным должен быть скрыт внутри вашего хранилища, иначе вы столкнетесь с проблемами.

Скажем, например, что ваш репозиторий (который инкапсулирует ваш ObjectContext) выходит из области видимости, после чего вы пытаетесь перечислить IQueryable результат, который дал вам репозиторий. Это приведет к ошибке, потому что IQueryable больше не может быть выполнен.

Если вы предоставляете IQueryable из своего репозитория, вы предоставляете конечному пользователю вашего репозитория всю свободу, которую он хочет при создании своих собственных запросов, чего вы хотите избежать, добавляя репозиторий!

Так что возвращать IEnumerable из вашего репозитория - это хорошо:)

0 голосов
/ 19 октября 2011

Я не вижу разницы в этих двух запросах. Однако, я думаю, вы хотите вернуть клиенту объект IQueryable, чтобы клиент мог выполнить дальнейшую фильтрацию и получить отсчет.

Вы можете просто вернуть объект, не делая выбора, и позволить клиенту сделать все остальное.

return _context.Comments

Клиент может выполнить дополнительную фильтрацию для этого объекта IQueryable

...