EF Core 2.1, запрос linq не создает группу по запросу sql, и я наконец вижу только Order By - PullRequest
1 голос
/ 27 июня 2019

У меня есть запрос linq, в котором есть предложение Group By, но Group SQL не выполняется на сервере sql. Я попытался простой запрос, и Group By происходит на сервере SQL. Пожалуйста, объясните мне, почему это другое поведение? Я хочу, чтобы эта группа на сервере для улучшения производительности.

Простой запрос, в котором я получаю групповые запросы, если я регистрирую SQL-запрос:

var testt = (from doc in _patientRepository.Documents
                     group doc by doc.DocumentType into G
                     select new
                     {
                         Key = G.Key

                     }).ToList();

Сгенерированный sql:

Executed DbCommand (247ms) [Parameters=[], CommandType='Text', 
CommandTimeout='30']
SELECT [doc].[DocumentType] AS [Key]
FROM [Document] AS [doc]
GROUP BY [doc].[DocumentType]

Запрос на выдачу:

var patX = (from doc in _patientRepository.Documents
                                               join pat in _patientRepository.Patients
                                               on doc.PatientId.ToString().ToLower() equals pat.PatientId.ToString().ToLower()
                                               where doc.Source.ToLower() != "testclient.server.postman" &&
                                               pat.Deleted == false && sfHCPs.Contains(pat.HcpId.ToLower())
                                               select new Document()
                                               {
                                                   DocumentId = doc.DocumentId,
                                                   CreationDateTime = doc.CreationDateTime,
                                                   DocumentType = doc.DocumentType,
                                                   PatientId = doc.PatientId,
                                                   DocumentTypeVersion = doc.DocumentTypeVersion,
                                                   Source = doc.Source,
                                                   PayloadLeft = DocumentMapper.DeserializePayload(doc.PayloadLeft),
                                                   PayloadRight = DocumentMapper.DeserializePayload(doc.PayloadRight),
                                                   PayloadBoth = DocumentMapper.DeserializePayload(doc.PayloadBoth),
                                                   IsSalesforceSynced = doc.IsSalesforceSynced,
                                                   HcpId = pat.HcpId
                                               }).GroupBy(p => new { p.PatientId, p.DocumentType })
        .Select(g => g.OrderByDescending(p => p.CreationDateTime).FirstOrDefault())
        .Where(x => x.IsSalesforceSynced == false)
        .ToList();

Почему он не сгенерировал sql для группировки:

Microsoft.EntityFrameworkCore.Database.Command[20101]
Executed DbCommand (200ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
SELECT [doc].[DocumentId], [doc].[CreationDateTime], [doc].[DocumentType], [doc].[PatientId], [doc].[DocumentTypeVersion], [doc].[Source], [doc].[PayloadLeft], [doc].[PayloadRight], [doc].[PayloadBoth], [doc].[IsSalesforceSynced], [pat].[HcpId]
FROM [Document] AS [doc]
INNER JOIN [Patient] AS [pat] ON LOWER(CONVERT(VARCHAR(36), [doc].[PatientId])) = LOWER(CONVERT(VARCHAR(36), [pat].[PatientId]))
WHERE ((LOWER([doc].[Source]) <> N'testclient.server.postman') AND ([pat].[Deleted] = 0)) AND LOWER([pat].[HcpId]) IN (N'4e7103a9-7dff-4fa5-b540-a32a31be2997', N'abc1', N'def2', N'ghi3')
ORDER BY [doc].[PatientId], [doc].[DocumentType]

Я попробовал следующий подход, но сгенерировал тот же SQL:

    var patX = ((from doc in _patientRepository.Documents
                                                       join pat in _patientRepository.Patients
                                                       on doc.PatientId.ToString().ToLower() 
                                                       equals pat.PatientId.ToString().ToLower()
                                                       where doc.Source.ToLower() != "testclient.server.postman" &&
                                                       pat.Deleted == false && sfHCPs.Contains(pat.HcpId.ToLower())
                                                       select new Document()
                                                       {
                                                           DocumentId = doc.DocumentId,
                                                           CreationDateTime = doc.CreationDateTime,
                                                           DocumentType = doc.DocumentType,
                                                           PatientId = doc.PatientId,
                                                           DocumentTypeVersion = doc.DocumentTypeVersion,
                                                           Source = doc.Source,
                                                           PayloadLeft = DocumentMapper.DeserializePayload(doc.PayloadLeft),
                                                           PayloadRight = DocumentMapper.DeserializePayload(doc.PayloadRight),
                                                           PayloadBoth = DocumentMapper.DeserializePayload(doc.PayloadBoth),
                                                           IsSalesforceSynced = doc.IsSalesforceSynced,
                                                           HcpId = pat.HcpId
                                                       }).GroupBy(p => new { p.PatientId, p.DocumentType })
                .Select(g => g.OrderByDescending(p => p.CreationDateTime).FirstOrDefault())
                .Where(x => x.IsSalesforceSynced == false))
                .ToList();

Ответы [ 2 ]

0 голосов
/ 01 июля 2019

Попробуйте переупорядочить запрос, чтобы select для нового класса был последним:

var p1 = from doc in _patientRepository.Documents
         join pat in _patientRepository.Patients on doc.PatientId.ToString().ToLower() equals pat.PatientId.ToString().ToLower()
         where doc.Source.ToLower() != "testclient.server.postman" && pat.Deleted == false && sfHCPs.Contains(pat.HcpId.ToLower())
         group new { doc, pat.HcpId } by new { doc.PatientId, doc.DocumentType } into dpg
         select dpg.OrderByDescending(dp => dp.doc.CreationDateTime).FirstOrDefault();

var patX = (from dp in p1
            where !dp.doc.IsSalesforceSynced
            select new Document() {
                DocumentId = dp.doc.DocumentId,
                CreationDateTime = dp.doc.CreationDateTime,
                DocumentType = dp.doc.DocumentType,
                PatientId = dp.doc.PatientId,
                DocumentTypeVersion = dp.doc.DocumentTypeVersion,
                Source = dp.doc.Source,
                PayloadLeft = DocumentMapper.DeserializePayload(dp.doc.PayloadLeft),
                PayloadRight = DocumentMapper.DeserializePayload(dp.doc.PayloadRight),
                PayloadBoth = DocumentMapper.DeserializePayload(dp.doc.PayloadBoth),
                IsSalesforceSynced = dp.doc.IsSalesforceSynced,
                HcpId = dp.HcpId
            })
            .ToList();
0 голосов
/ 30 июня 2019

До версии 2.1 в EF Core оператор GroupBy LINQ всегда оценивался в памяти. Теперь в большинстве распространенных случаев поддерживается его перевод в предложение SQL GROUP BY.

изменить код: попробуйте разместить .GroupBy перед .select методом (сначала выберите)

...