OrderBy отношения многие ко многим с Entity Sql - PullRequest
1 голос
/ 05 марта 2012

Я пытаюсь лучше использовать ресурсы Entity Sql в следующем сценарии: у меня есть таблица Book, которая имеет отношение «многие ко многим» с таблицей Author. Каждая книга может иметь от 0 до N авторов. Я хотел бы отсортировать книги по имени первого автора, то есть по первой записи, найденной в этом отношении (или null , когда ни один автор не связан с книгой).

С T-SQL это можно сделать без труда:

SELECT
    b.*
FROM
    Book AS b
    JOIN BookAuthor AS ba ON b.BookId = ba.BookId
    JOIN Author AS a ON ba.AuthorId = a.AuthorId
ORDER BY
    a.AuthorName;

Но я не могу придумать, как адаптировать мой код ниже для его достижения. На самом деле я не знаю, как написать что-то эквивалентное напрямую с Entity Sql .

Entities e = new Entities();
var books = e.Books;
var query = books.Include("Authors");

if (sorting == null)
    query = query.OrderBy("it.Title asc");
else
    query = query.OrderBy("it.Authors.Name asc"); // This isn't it.

return query.Skip(paging.Skip).Take(paging.Take).ToList();

Может ли кто-нибудь объяснить мне, как изменить мой код, чтобы сгенерировать Entity Sql для желаемого результата? Или даже объясните мне, как написать вручную запрос, используя CreateQuery<Book>() для его достижения?

EDIT

Просто чтобы прояснить, я буду работать с очень большой коллекцией книг (около 100 тыс.). Сортировка их в памяти будет очень влиять на производительность. Я хотел бы, чтобы ответы были сосредоточены на том, как сгенерировать желаемый порядок, используя Entity Sql, , поэтому порядок будет происходить в базе данных .

Ответы [ 2 ]

3 голосов
/ 05 марта 2012

Метод OrderBy ожидает, что вы дадите ему лямбда-выражение (ну, на самом деле, делегат Func, но большинство людей будут использовать лямбда-выражения для его создания), которое можно запустить, чтобы выбрать поле для сортировки. Кроме того, OrderBy всегда заказывает по возрастанию; если вам нужен нисходящий порядок, есть метод OrderByDescending.

var query = books
  .Include("Authors")
  .OrderBy(book => book.Authors.Any()
    ? book.Authors.FirstOrDefault().Name
    : string.Empty);

Это в основном говорит метод OrderBy: «для каждой книги в последовательности, если есть какие-либо авторы, выберите имя первой в качестве ключа сортировки; в противном случае выберите пустую строку. Затем верните мне книги, отсортированные по Ключ сортировки. "

Вы можете поместить все вместо string.Empty, включая, например, book.Title или любое другое свойство книги, чтобы использовать вместо фамилии для сортировки.

РЕДАКТИРОВАТЬ из комментариев:

Пока запрашиваемое поведение сортировки не слишком сложно, поставщик запросов Entity Framework обычно может выяснить, как превратить его в SQL. Он будет действительно очень стараться, и если это не удастся, вы получите ошибку запроса. Единственный раз, когда сортировка будет выполняться в объектах на стороне клиента, - это если вы принудительно выполняете запрос (например, .AsEnumerable()) до вызова OrderBy.

В этом случае EF выводит оператор выбора, который включает в себя следующее вычисляемое поле:

    CASE WHEN ( EXISTS (SELECT 
        1 AS [C1]
        FROM [dbo].[BookAuthor] AS [Extent4]
        WHERE [Extent1].[Id] = [Extent4].[Books_Id]
    )) THEN [Limit1].[Name] ELSE @p__linq__0 END AS [C1], 

Тогда заказы по этому.

@p__linq__0 - это параметр, передаваемый как string.Empty, так что вы можете видеть, что он довольно напрямую преобразует лямбда-выражение в SQL. Экстент и Лимит - это просто псевдонимы, используемые в сгенерированном SQL для объединенных таблиц и т. Д. Extent1 - это [Books], а Limit1 - это:

SELECT TOP (1) -- Field list goes here.
FROM  [dbo].[BookAuthor] AS [Extent2]
INNER JOIN [dbo].[Authors] AS [Extent3] ON [Extent3].[Id] = [Extent2].[Authors_Id]
WHERE [Extent1].[Id] = [Extent2].[Books_Id] 
0 голосов
/ 05 марта 2012

Если вас не волнует, где происходит сортировка (т. Е. SQL против кода), вы можете получить свой набор результатов и отсортировать его, используя собственный код сортировки после того, как результаты запроса будут возвращены.По моему опыту, подобная специализированная сортировка для работы с Entity Framework может быть очень сложной, разочаровывающей и отнимающей много времени.

...