I have a linq query which has Group By clause, but the Group By is not happening on sql server. I tried a simple query and the Group By is happening on sql server. Please guide me why this different behavior?? I want that group-by on server for performance improvement.
Simple query where I get group-by if I log the sql query:
var testt = (from doc in _patientRepository.Documents
group doc by doc.DocumentType into G
select new
{
Key = G.Key
}).ToList();
Generated sql:
Executed DbCommand (247ms) [Parameters=[], CommandType='Text',
CommandTimeout='30']
SELECT [doc].[DocumentType] AS [Key]
FROM [Document] AS [doc]
GROUP BY [doc].[DocumentType]
Issue query:
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();
Why don't it have group-by sql generated:
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]
I tried below approach but same sql generated:
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();
Before version 2.1, in EF Core the GroupBy LINQ operator would always be evaluated in memory.Now support translating it to the SQL GROUP BY clause in most common cases.
change code : try to place .GroupBy before .select method(first select)