EF Core 2.1,linq查询无法按SQL查询生成分组,最后我只能看到Order By

时间:2019-06-27 15:25:00

标签: entity-framework linq-to-sql entity-framework-core linq-to-entities entity-framework-core-2.1

我有一个具有Group By子句的linq查询,但是Group By不在SQL Server上发生。 我尝试了一个简单的查询,并且在SQL Server上发生了分组依据。 请指导我为什么这种不同的行为?? 我希望在服务器上进行分组以提高性能。

  

如果我登录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();
  

为什么没有生成group-by 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 :(得分:0)

在2.1版之前,在EF Core中,GroupBy LINQ运算符将始终在内存中进行评估。现在,在大多数情况下,现在支持将其转换为SQL GROUP BY子句。

更改代码:尝试将.GroupBy放在.select方法之前(首先选择)

答案 1 :(得分:0)

考虑对查询重新排序,以使新类的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();