Оператор Linq с проекцией на класс, ЗАТЕМ GroupBy приводит к локальной оценке

#c# #linq #entity-framework-core

#c# #linq #entity-framework-core

Вопрос:

Я отправляю IQueryable методу, который анализирует данные для таблиц данных jQuery. Он создает фильтр из данных ФОРМЫ и создает оператор LINQ с фильтром, сортировкой, подкачкой и т.д., Который Отправляется обратно на страницу в виде JSON. Я хотел бы расширить анализатор и добавить итоговые значения в результирующий набор. Когда я добавляю оператор GroupBy, запрос вычисляется не на сервере, а локально. Он будет выполняться только на сервере, если исходный IQueryable имеет анонимную проекцию…

Это веб-сайт .Net Core 2.1. Я знаю, что в прошлом GroupBy не мог быть выполнен локально, но это происходит на уровне 2.1. Я пробовал проекцию с классом и на анонимный тип, и это работает должным образом только с анонимным типом. Мне действительно нужно иметь возможность делать это с классом.

Следующий IQueryable отправляется синтаксическому анализатору:

 var query = Context.InvoiceHeaders
     .AsNoTracking()
     .Where(x=>x.Slsno.Equals("13"))
     .Select(x => new InvoiceHeaderSummary()
     {
         SalesNumber = x.Slsno,
         OrderNumber = x.Ordnum,
         ItemAmount = x.Itmamt,
         SpecialChargeAmount = x.Sc1amt,
         TaxAmount = x.Taxamt,
         InvoiceTotal = x.Invamt
     })

var parser = new Parser<InvoiceHeaderSummary>(Request.Form, query);
  

Я пытаюсь расширить анализатор, добавив список итогов к выходным данным. Но поскольку я отправляю IQueryable с проекцией класса (InvoiceHeaderSummary), он не выполняется на сервере. Я получаю предупреждение о том, что оно оценивается локально:

 var totalList = query
     .GroupBy(i => 1)
     .Select(g => new
     {
          TotalInvoice = g.Sum(i => i.InvoiceTotal)
     })
     .ToList();
  

Я попытался создать весь встроенный метод LINQ, и он работает правильно (обратите внимание, что я использую анонимную проекцию перед классом GroupBy, а не InvoiceHeaderSummary):

 var query = Context.InvoiceHeaders
     .AsNoTracking()
     .Where(x=>x.Slsno.Equals("13"))
     .Select(x => new
     {
         SalesNumber = x.Slsno,
         OrderNumber = x.Ordnum,
         ItemAmount = x.Itmamt,
         SpecialChargeAmount = x.Sc1amt,
         TaxAmount = x.Taxamt,
         InvoiceTotal = x.Invamt
     })
     .GroupBy(i => 1)
     .Select(g => new
     {
          TotalInvoice = g.Sum(i => i.InvoiceTotal)
     })
     .ToList();
  

Есть ли способ правильно написать это, чтобы оно работало оптимально??

Ответ №1:

По-видимому, один из дефектов / багов перевода запросов EF Core 2.x.

Единственное решение, которое я нашел, — использовать GroupBy перегрузку с помощью селектора элементов и выбрать данные, которые вы хотите объединить в анонимный тип:

 var totalList = query
     .GroupBy(i => 1, i => new { i.InvoiceTotal }) // <--
     .Select(g => new
     {
          TotalInvoice = g.Sum(i => i.InvoiceTotal)
     })
     .ToList();