我有这个SQL查询,我试图将其转换为Linq
var result =
(from ce in ControlEvents
join pe in ProcessEvents on ce.Id equals pe.ControlEventId
join rt in ResultTypes on pe.ResultTypeId equals rt.Id into resultType
where ce.DueDate >= startDate &&
ce.DueDate <= endDate &&
pe.ProcessId == 1048
orderby ce.DueDate.Value.Year, ce.DueDate.Value.Month
group ce by new {
ce.DueDate.Value.Year,
ce.DueDate.Value.Month,
} into g
select new {
g.Key.Year,
g.Key.Month,
}
).ToList();
到目前为止我已经这样做了
{{1}}
我的问题是如何将我的SQL查询中的case语句带到linq Select。感谢。
答案 0 :(得分:2)
首先,删除into resultType
,因为它会创建一个组连接,并且您的SQL查询不会使用此类构造。
其次,在orderby
之后移动groupby
子句。
最后,使用SQL Count(CASE WHEN condition THEN 1 ELSE NULL END)
等同于LINQ支持的SUM(condition, 1, 0)
这一事实。
所以等效的LINQ查询可能是这样的:
var result =
(from ce in ControlEvents
join pe in ProcessEvents on ce.Id equals pe.ControlEventId
join rt in ResultTypes on pe.ResultTypeId equals rt.Id
where ce.DueDate >= startDate &&
ce.DueDate <= endDate &&
pe.ProcessId == 1048
group rt by new {
ce.DueDate.Value.Year,
ce.DueDate.Value.Month,
} into g
orderby g.Key.Year, g.Key.Month
select new {
g.Key.Year,
g.Key.Month,
NumPass = g.Sum(e => e.Code == "Pass" ? 1 : 0),
NumFail = g.Sum(e => e.Code == "Fail" ? 1 : 0)
}
).ToList();
生成的EF6.1.3生成的SQL查询如下所示:
SELECT
[Project1].[C5] AS [C1],
[Project1].[C3] AS [C2],
[Project1].[C4] AS [C3],
[Project1].[C1] AS [C4],
[Project1].[C2] AS [C5]
FROM ( SELECT
[GroupBy1].[A1] AS [C1],
[GroupBy1].[A2] AS [C2],
[GroupBy1].[K1] AS [C3],
[GroupBy1].[K2] AS [C4],
1 AS [C5]
FROM ( SELECT
[Filter1].[K1] AS [K1],
[Filter1].[K2] AS [K2],
SUM([Filter1].[A1]) AS [A1],
SUM([Filter1].[A2]) AS [A2]
FROM ( SELECT
DATEPART (year, [Extent1].[DueDate]) AS [K1],
DATEPART (month, [Extent1].[DueDate]) AS [K2],
CASE WHEN (N'Pass' = [Extent3].[Code]) THEN 1 ELSE 0 END AS [A1],
CASE WHEN (N'Fail' = [Extent3].[Code]) THEN 1 ELSE 0 END AS [A2]
FROM [dbo].[ControlEvents] AS [Extent1]
INNER JOIN [dbo].[ProcessEvents] AS [Extent2] ON [Extent1].[Id] = [Extent2].[ControlEventId]
INNER JOIN [dbo].[ResultTypes] AS [Extent3] ON [Extent2].[ResultTypeId] = [Extent3].[Id]
WHERE ([Extent1].[DueDate] >= @p__linq__0) AND ([Extent1].[DueDate] <= @p__linq__1) AND ([Extent2].[ProcessId] = @p__linq__2)
) AS [Filter1]
GROUP BY [K1], [K2]
) AS [GroupBy1]
) AS [Project1]
ORDER BY [Project1].[C3] ASC, [Project1].[C4] ASC
答案 1 :(得分:1)
你快到了。在您的select语句之前,您有一系列组,其中每个组是一系列连接结果,其中每个连接结果具有相同的年/月。
例如,您有以下组
您已经发现密钥包含您想要的年份和月份。
对于2015年1月组的NumPass,您希望2015年1月序列中的所有元素与joinResult.resultType.code ==“Pass”匹配,
作为一个面向对象的程序员,我总是在使用这一半SQL语法编写Linq语句时遇到一些困难,所以如果它不会打扰你太多,我会用lambda表达式重写它:
ControlEvents.Join(ProcessEvents,
key1 => key1.Id, // from ControlEvents take Id
key2 => key2.ControlEventId // from processEventt take ControlEventId
(x, y) => new // where they match,
{
DueDate = x.DueDate, // take ControlEvent.Duedate
ProcessId = y.ProcessId, // take ProcessId.Id
ResultTypeId = y.ResultTypeId, // take Process.ResultTypeId
})
.Where (joinResult => // limit the join result before the 2nd join
joinResult.DueDate >= startDate &&
joinResult.DueDate <= endDate &&
joinResult.ProcessId == 1048)
.Join(ResultTypes, // join the previous result with ResultTypes
key1 => key1.ResultTypeId // from previous join take ResultTypeId
key2 => key2.Id // from ResultTypes takd Id
(x, y) => new // where they match, take:
{
Year = x.DueDate.year,
Month = x.DueDate.Month,
// ProcessId = x.ProcessId, not needed anymore
// unless you want the where statement after the 2nd join
ResultCode = y.Code,
})
.Orderby(joinResult => joinResult.Year)
.ThenBy(joinResult => joinResult.Month)
.GroupBy(sortResult => new {Year = sortResult.Year, Month = sortResult.Month}
现在你要做的就是计算一组中与“通过”匹配的所有元素以及与“失败”匹配的元素:
继续LINQ声明:
.Select(group => new
{
Year = group.key.Year,
Month = group.key.Month,
NumPass = group
.Where(groupElement => groupElement.ResultCode.Equals("Pass"))
.Count(),
NumFail = group
.Where(groupElement => groupElement.ResultCode.Equals("Fail"))
.Count(),
}
.ToList();
这应该可以解决问题。
请注意,我在第二次加入之前将Where语句放入ProcessId == 1048,因为我猜这限制了要加入的项目数量。也许以下甚至更聪明:
ControlEvents
.Where(controlEvent => controlEvent.DueDate >= startDate
&& controlEvent.DueDate <= endDate)
.Join (ProcessEvents.Where(processEvent => processEvent.Id == 1048),
key1 => etc,
我想这确实会限制要加入的元素数量。
此外,考虑在最终选择之后按年/月排序,因为在这种情况下,您还必须订购更小的集合