我正在尝试将以下 SQL 转换为 IQueryable,这样我就可以在从数据库检索数据之前访问结果并根据不同条件进行过滤, 但我收到一个错误,无法翻译 LINQ 查询。
SELECT
a.Id AS HandymanId,
u.SubscriptionSource,
a.TrialExpiryDate,
COUNT(DISTINCT b.Id) AS PhoneCallCount,
COUNT(DISTINCT CASE WHEN b.RecordingSid IS NOT NULL AND b.RecordingSid <> '' THEN b.Id END) AS VoiceMessageCount,
COUNT(DISTINCT d.Id) AS AppointmentCount,
COUNT(DISTINCT e.Id) AS TodoCount,
COUNT(DISTINCT f.Id) AS DocumentationCount,
COUNT(DISTINCT g.Id) AS MessageCount
FROM
[dbo].[Handymen] a
LEFT JOIN
PhoneCalls b ON a.Id = b.HandymanId
LEFT JOIN
[Identity].[User] u ON u.Id = a.ApplicationUserId
LEFT JOIN
Projects c ON a.Id = c.HandymanId
LEFT JOIN
Appointments d ON c.Id = d.ProjectId
LEFT JOIN
Todos e ON e.ProjectId = c.Id
LEFT JOIN
Documentations f ON f.ProjectId = c.Id
LEFT JOIN
[Messages] g ON g.ProjectId = c.Id
GROUP BY
a.Id, u.SubscriptionSource, a.TrialExpiryDate;
from user in context.Handymen
join call in context.PhoneCalls on user.Id equals call.HandymanId into callGroup
join appointment in context.Appointments on user.Id equals appointment.Project.HandymanId into appointmentGroup
join todo in context.Todos on user.Id equals todo.Project.HandymanId into todoGroup
join documentation in context.Documentations on user.Id equals documentation.Project.HandymanId into documentationGroup
join enquiry in context.Projects on user.Id equals enquiry.HandymanId into enquiryGroup
join message in context.Messages on user.Id equals message.Project.HandymanId into messageGroup
where user.HandymanProTrialExpiryDate > DateTime.UtcNow
select new MyData
{
Id = user.Id,
CallCount = callGroup.Select(call => call.Id).Distinct().Count(),
AppointmentCount = appointmentGroup.Select(appointment => appointment.Id).Distinct().Count(),
TodoCount = todoGroup.Select(todo => todo.Id).Distinct().Count(),
DocumentationCount = documentationGroup.Select(documentation => documentation.Id).Distinct().Count(),
EnquiryCount = enquiryGroup.Select(enquiry => enquiry.Id).Distinct().Count(),
MessageCount = messageGroup.Select(message => message.Id).Distinct().Count()
}
无论 LINQ 是否可以翻译,我认为原始查询都不正确。
因此,您需要预先聚合连接,而不是使用
COUNT(DISTINCT
。
from user in context.Handymen
where user.HandymanProTrialExpiryDate > DateTime.UtcNow
let calls = context.PhoneCalls
.Where(call => user.Id == call.HandymanId)
.GroupBy(call => 0) // group by empty set
.Select(g => new { CallCount = g.Count(), VoiceMessageCount = g.Count(c => c.RecordingSid != "") })
select new MyData
{
Id = user.Id,
calls.CallCount,
calls.VoiceMessageCount,
AppointmentCount = context.Appointments.Where(app => user.Id == app.Project.HandymanId).Count(),
TodoCount = context.Todos(todo => user.Id == todo.Project.HandymanId).Count(),
DocumentationCount = context.Documentations.Where(doc => user.Id == doc.Project.HandymanId).Count(),
MessageCount = context.Messages.Where(msg => user.Id == msg.Project.HandymanId).Count()
}
理想情况下,您将能够使用导航属性:
from user in context.Handymen
where user.HandymanProTrialExpiryDate > DateTime.UtcNow
let calls = user.PhoneCalls
.GroupBy(call => 0) // group by empty set
.Select(g => new { CallCount = g.Count(), VoiceMessageCount = g.Count(c => c.RecordingSid != "") })
select new MyData
{
Id = user.Id,
calls.CallCount,
calls.VoiceMessageCount,
AppointmentCount = user.Projects.SelectMany(p => p.Appointments).Count(),
TodoCount = user.Projects.SelectMany(p => p.Todos).Count(),
DocumentationCount = user.Projects.SelectMany(p => p.Documentations).Count(),
MessageCount = user.Projects.SelectMany(p => p.Messages).Count()
}
你甚至可以预先聚合
Projects
,这可能会更有效
from user in context.Handymen
where user.HandymanProTrialExpiryDate > DateTime.UtcNow
let calls = user.PhoneCalls
.GroupBy(call => 0) // group by empty set
.Select(g => new { CallCount = g.Count(), VoiceMessageCount = g.Count(c => c.RecordingSid != "") })
let projects = user.Projects
.Select(p => new
{
AppointmentCount = p.Appointments.Count(),
TodoCount = p.Todos.Count(),
DocumentationCount = p.Documentations.Count(),
MessageCount = p.Messages.Count()
})
.GroupBy(p => 0) // group by empty set
.Select(g => new
{
AppointmentCount = g.Sum(p => p.AppointmentCount),
TodoCount = g.Sum(p => p.TodoCount),
DocumentationCount = g.Sum(p => p.DocumentationCount),
MessageCount = g.Sum(p => p.MessageCount)
})
select new MyData
{
Id = user.Id,
calls.CallCount,
calls.VoiceMessageCount,
projects.AppointmentCount,
projects.TodoCount,
projects.DocumentationCount,
projects.MessageCount,
}