Как группировать данные из многих таблиц в базовом Entity Framework до tnet - PullRequest
3 голосов
/ 20 апреля 2020

Я создаю какое-то рыночное веб-приложение, скажем, что-то вроде e-bay. Типичный сценарий:

Пользователь делает предложение, которое состоит из одного или нескольких элементов, и эти элементы имеют определенный тип. После этого другие пользователи делают ставки на это предложение.

Вот упрощенная схема.

diagram

Вкл. SQL Fiddle ( здесь ), вы можете увидеть оба Операторы CREATE TABLE и INSERT INTO

Пример данных: Есть два предложения. На одно предложение (Id 1), который состоит из одного предмета типа «часы». Есть еще одно предложение (Id 2), в котором есть один предмет типа «наушники». На оба предложения есть ставки. На часах есть два бис; одна ставка - 100 долларов, другая - 120. На наушники есть ставки 50 и 80 долларов.

Я хочу добиться средней ставки для каждого типа. В данном примере это означает, что я хочу получить 110 в качестве средней ставки для часов и 65 в качестве средней ставки для наушников. Чтобы добиться этого, используя T- SQL, я написал бы запрос следующим образом:

SELECT t.name,
       avg(amount)
FROM bid b
LEFT JOIN offer o ON b.OfferId = o.id
LEFT JOIN offeritem oi ON o.id = oi.OfferId
LEFT JOIN itemType t ON oi.itemtypeid = t.Id
GROUP BY t.name

Итак, мой вопрос - как этого добиться в do tnet core 3.0 EntityFramework

Использование GroupBy, например:

_context.Bids
    .Include(b => b.Offer)
        .ThenInclude(o => o.OfferItems)
            .ThenInclude(os => os.ItemType)
    .GroupBy(b => b.Offer.OfferItems.First().ItemType.Name);

дает исключение:

Клиентская группа GroupBy не поддерживается.

. Когда я пытаюсь с проекцией, вот так:

_context.Bids
    .Include(b => b.Offer)
        .ThenInclude(o => o.OfferItems)
            .ThenInclude(os => os.ItemType)
    .GroupBy(b => b.Offer.OfferItems.First().ItemType.Name)
    .Select(g => new
    {
        Key = g,
        Value = g.Average(b => b.Amount)
    });

я снова получаю исключение.

Обработка LINQ .... не выполнена. Это может указывать на ошибку или ограничение в EF Core.

РЕДАКТИРОВАТЬ:

Этот подход

_context.Bids
    .Include(b => b.Offer)
        .ThenInclude(o => o.OfferItems)
            .ThenInclude(os => os.ItemType)
    .GroupBy(b => new { b.Offer.OfferItems.First().ItemType.Name}, b => b.Amount)
    .Select(g => new
    {
        Key = g.Key.Code,
        Value = g.Average()
    });

также бросил исключение, но на этот раз:

Невозможно использовать агрегат или подзапрос в выражении, используемом для группы по списку предложения GROUP BY.

...

Итак, есть ли способ сгруппировать эти данные (получить простое среднее значение) или мне следует сделать другой запрос, выполнить итерацию сбора и произвести расчеты самостоятельно? Это наверняка снизит производительность (я надеялся, что смогу группировать серверы, но, как вы видите, я столкнулся с упомянутыми проблемами). Любые идеи? Заранее спасибо.

1 Ответ

1 голос
/ 20 апреля 2020

В вашем случае трудно скрыть подзапрос от группировки

Вы можете попробовать его таким образом

var joined =
    context.Bid
        .SelectMany(x =>
            x.Offer.OfferItem
                .Select(y => new
                {
                    Amount = x.Amount,
                    Name = y.ItemType.Name
                })
                .Take(1));

var grouped = from i in joined
    group i by i.Name into groups
    select new
    {
        Key = groups.Key,
        Amount = groups.Average(x => x.Amount)
    };

он дает мне запрос

SELECT [t].[Name] AS [Key], AVG([t].[Amount]) AS [Amount]
  FROM [Bid] AS [b]
  INNER JOIN [Offer] AS [o] ON [b].[OfferId] = [o].[Id]
  CROSS APPLY (
      SELECT TOP(1) [b].[Amount], [i].[Name], [o0].[Id], [i].[Id] AS [Id0], [o0].[OfferId]
      FROM [OfferItem] AS [o0]
      INNER JOIN [ItemType] AS [i] ON [o0].[ItemTypeId] = [i].[Id]
      WHERE [o].[Id] = [o0].[OfferId]
  ) AS [t]
  GROUP BY [t].[Name]
...