. Net Ядро 3.1. Нужна вложенная группа По номенклатуре за день Количество Показать - PullRequest
1 голос
/ 09 июля 2020

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

  return [
      {
        name: 'Shoes',
        data: [502, 635, 809, 947, 1402, 3634, 5268],
      },
      {
        name: 'Africa',
        data: [106, 107, 111, 133, 221, 767, 1766],
      },
      {
        name: 'tshirt',
        data: [163, 203, 276, 408, 547, 729, 628],
      },
      {
        name: 'pants',
        data: [18, 31, 54, 156, 339, 818, 1201],
      },
      {
        name: 'Oceania',
        data: [2, 2, 2, 6, 13, 30, 46],
      },
    ];

Мой код:

   IReadOnlyList<OrderItemReportDto> query = await _context.OrderItems
                                    .GroupBy(x => new { x.ItemOrdered.ProductType })
                                         .Select(y => new OrderItemReportDto
                                         {
                                             Name = y.Key.ProductType,
                                             Quantity = y.Sum(c => c.Quantity),
                                             Count = y.GroupBy(x => x.CreatedTime.Date).Select(x => x.Sum(c => c.Quantity)).ToArray()
                                         })
                                         .ToListAsync();
        return query;

OrderItemReportDto:

   public class OrderItemReportDto
    {
        public string Name { get; set; }
        public int Quantity { get; set; }
        public int[] Count { get; set; }
    }

Order Items :
 

  public class OrderItem : BaseEntity
    {
        public OrderItem()
        {
        }

        public OrderItem(OrderProductItem ıtemOrdered, decimal price, int quantity)
        {
            ItemOrdered = ıtemOrdered;
            Price = price;
            Quantity = quantity;
            CreatedTime = DateTime.Now;
        }

        public OrderProductItem ItemOrdered { get; set; }
        public decimal Price { get; set; }
        public int Quantity { get; set; }
        public DateTime CreatedTime
        {
            get
            {
                return this.dateCreated.HasValue
                   ? this.dateCreated.Value
                   : DateTime.Now;
            }

            set { this.dateCreated = value; }
        }
        private DateTime? dateCreated = null;

    }

но ошибка:

{
    "StatusCode": 500,
    "Message": "The LINQ expression '(GroupByShaperExpression:\r\nKeySelector: new { ProductType = (t.ItemOrdered_ProductType) }, \r\nElementSelector:(EntityShaperExpression: \r\n    EntityType: OrderItem\r\n    ValueBufferExpression: \r\n        (ProjectionBindingExpression: EmptyProjectionMember)\r\n    IsNullable: False\r\n)\r\n)\r\n    .GroupBy(x => x.CreatedTime.Date)' could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to either AsEnumerable(), AsAsyncEnumerable(), ToList(), or ToListAsync(). See https://go.microsoft.com/fwlink/?linkid=2101038 for more information."
}

1 Ответ

0 голосов
/ 09 июля 2020

Когда вы используете _context.OrderItems.GroupBy, компилятор использует метод расширения GroupBy из IQueryable.

Когда вы запускаете свою программу, среда выполнения попытается преобразовать выражения LINQ в запрос SQL . Однако не все выражения LINQ можно преобразовать в запрос SQL, и поэтому вы получите исключение.

Однако, если вы используете IEnumerable, среда выполнения не будет генерировать выражение SQL . Вместо этого он загрузит все элементы в память, а затем применит ваши выражения LINQ к этим коллекциям.

Попробуйте изменить на

var query = context.OrderItems.AsEnumerable()
    .GroupBy(x => new {x.ItemOrdered.ProductType})
    .Select(y => new OrderItemReportDto
    {
        Name = y.Key.ProductType,
        Quantity = y.Sum(c => c.Quantity),
        Count = y.GroupBy(x => x.CreatedTime.Date).Select(x => x.Sum(c => c.Quantity)).ToArray()
    })
    .ToList();

Теперь имейте в виду, что это будет дорогостоящая операция, поскольку вы загрузите все элементы в память, а затем примените предложения LINQ. Это означает, что все поля / столбцы, которые могут вам не понадобиться, также будут загружены в память. Если вы выполняете какие-либо операции фильтрации с использованием Where, вы можете попробовать выполнить их перед преобразованием запроса в IEnumerable

Я использую ToList() выше, потому что ToListAsync() недоступен для IEnumerable.

Если вам действительно нужно использовать asyn c, вы можете сделать это

var query = context.OrderItems.AsEnumerable()
    .GroupBy(x => new {x.ItemOrdered.ProductType})
    .Select(y => new OrderItemReportDto
    {
        Name = y.Key.ProductType,
        Quantity = y.Sum(c => c.Quantity),
        Count = y.GroupBy(x => x.CreatedTime.Date).Select(x => x.Sum(c => c.Quantity)).ToArray()
    }).AsQueryable()
    .ToListAsync();

Однако я не думаю, что этот async обходной путь что-то вам даст.

...