Группировка соединенных таблиц - PullRequest
1 голос
/ 27 мая 2019

Я пытаюсь объединить таблицы продуктов и атрибутов и сгруппировать их по идентификатору продукта, чтобы получить список продуктов с их атрибутами.Поэтому я попробовал следующий запрос Entity Framework:

    var productsWithAttributes = (from product in ctx.products
                                  join attribute in ctx.attributes on product.id equals attribute.productId
                                  select new
                                     {
                                          product = product,
                                          a1 = attribute.a1,
                                          a2 = attribute.a2,
                                          a3 = attribute.a3,
                                          a4 = attribute.a4
                                  } into t
                                  group t by t.product.id into g
                                     select new
                                     {
                                         product = g.Select(p => p.product).FirstOrDefault(),
                                         attributes = g.Select(r => new Attr()
                                         {
                                             a1 = r.a1,
                                             a2 = r.a2,
                                             a3 = r.a3,
                                             a4 = r.a4
                                         }).ToList()
                                     }
                                    ).ToList();

Но это заняло около 70 минут, и когда я посмотрел на полученный SQL-запрос, я увидел десятки подзапросов с десятками объединений.

Затем я попытался выполнить группировку на сервере sql и сделал проекцию на нужную структуру на сервере приложений.И это код EF для этого:

    var productsWithAttributes = (from product in ctx.products
                                  join attribute in ctx.attributes on product.id equals attribute.productId
                                  select new
                                      {
                                          product = product,
                                          a1 = attribute.a1,
                                          a2 = attribute.a2,
                                          a3 = attribute.a3,
                                          a4 = attribute.a4
                                  } into t
                                      group t by t.product.id

                            ).ToList();

Это заняло около 3 минут.Но SQL, созданный этим запросом, все еще выглядит сложным с несколькими подзапросами и объединениями.Я хотел бы увидеть что-то вроде:

select product.*, attribute.a1, attribute.a2, attribute.a3, attribute.a4
from product
join attribute on product.id = attribute.productId
group by product.id

Затем я попытался просто объединить без группировки:

    var productsWithAttributes = (from product in ctx.products
                                      join attribute in ctx.attributes on product.id equals attribute.productId
                                      select new
                                      {
                                          product = product,
                                          a1 = attribute.a1,
                                          a2 = attribute.a2,
                                          a3 = attribute.a3,
                                          a4 = attribute.a4,

                                      }
                                    ).ToList();

Это заняло 1,5 минуты, и код SQL, созданный EF, был, как ожидалось.

Короче говоря, добавление группировки в объединение создает сложный SQL-запрос, который занимает больше времени, но все еще приемлем с точки зрения производительности.Но добавление окончательного прогноза после этой группировки приводит к невероятно запутанному SQL-запросу, который занимает недопустимое количество времени.

Как правильно создать этот запрос с EF?

Ответы [ 2 ]

1 голос
/ 28 мая 2019

Рекомендуемый способ создания такого запроса в LINQ to Entities - использовать свойство навигации по коллекции или, в случае его отсутствия, - Объединение в группу construct (join ... into):

Объединение группы создает иерархическую результирующую последовательность, которая связывает элементы в левой исходной последовательности с одним или несколькими совпадающими элементами в правой стороне исходной последовательности.Групповое объединение не имеет эквивалента в реляционных терминах;по сути это последовательность массивов объектов.

Примерно так:

var productsWithAttributes = (
    from product in ctx.products
    join attribute in ctx.attributes on product.id equals attribute.productId
    into attributes // <-- emulate product.attributes property
    select new
    {
        product = product,
        attributes = attributes.Select(attribute => new Attr()
        {
            a1 = attribute.a1,
            a2 = attribute.a2,
            a3 = attribute.a3,
            a4 = attribute.a4
         }).ToList(),
     }).ToList();
1 голос
/ 27 мая 2019

Если вы хотите создать объединенные таблицы, то все, что вам нужно сделать, это создать еще одну таблицу с обоими pk (ключами Primay) и полным объединением, а не внутренним объединением или просто объединением.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...