无法 select 分组 Entity Framework
not able to select in Group by Entity Framework
我有这个 SQL 查询,我正试图将其翻译成 Linq
SELECT
DATEPART(yyyy, ce.DueDate) AS year,
DATEPART(mm, ce.DueDate) AS Month,
COUNT(CASE WHEN rt.Code = 'Pass' THEN 1 ELSE NULL END) AS NumPass,
COUNT(CASE WHEN rt.Code = 'Fail' THEN 1 ELSE NULL END) AS NumFail
FROM
ControlEvent ce
INNER JOIN
ProcessEvent pe ON pe.ControlEventId = ce.Id
INNER JOIN
ResultType rt ON pe.ResultTypeId = rt.Id
WHERE
DATEDIFF(dd,ce.DueDate,GETDATE()) <= 0
AND DATEDIFF(dd,ce.DueDate,DATEADD(mm, 3, GETDATE())) >= 0
AND pe.ProcessId = 1040
GROUP BY
DATEPART(yyyy, ce.DueDate), DATEPART(mm, ce.DueDate)
ORDER BY
DATEPART(yyyy, ce.DueDate), DATEPART(mm, ce.DueDate)
到目前为止我已经这样做了
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();
我的问题是如何将我的 SQL 查询中的 case 语句带到 linq Select。谢谢
首先,删除 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
你快到了。就在您的 select 语句之前,您有一系列组,其中每个组都是一系列连接结果,其中每个连接结果具有相同的年份/月份。
例如,您有以下组
- group1(2015 年 1 月)= 截止日期为 2015 年 1 月的连接结果序列
- group2(2015 年 2 月)= 截止日期为 2015 年 2 月的连接结果序列
- group3(2015 年 2 月)= 截止日期为 2015 年 3 月的连接结果序列
您已经发现密钥中包含您想要的年份和月份。
对于 2015 年 1 月组的 NumPass,您需要 2015 年 1 月序列中匹配 joinResult.resultType.code == "Pass"、
的所有元素
作为一个面向对象的程序员,我在写我的 Linq 语句时总是有点困难 SQL 这样的语法,所以如果你不介意的话,我用 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}
- 现在你有关键字为 {Year, Month} 的组。
- 每个组都有一系列具有属性 { Year, Month, ResultCode} 的对象
- 一组内的年/月都一样
现在您所要做的就是计算一组中匹配 "Pass" 和匹配 "Fail" 的所有元素:
继续 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();
这应该可以解决问题。
请注意,我将 ProcessId == 1048 的 Where 语句放在第二次加入之前,因为我猜这会限制要加入的项目数量。也许以下甚至会更聪明:
ControlEvents
.Where(controlEvent => controlEvent.DueDate >= startDate
&& controlEvent.DueDate <= endDate)
.Join (ProcessEvents.Where(processEvent => processEvent.Id == 1048),
key1 => etc,
我想这真的会限制加入的元素数量。
此外,请考虑在最终 select 之后按年/月排序,因为那样的话您还必须对更小的系列进行排序
我有这个 SQL 查询,我正试图将其翻译成 Linq
SELECT
DATEPART(yyyy, ce.DueDate) AS year,
DATEPART(mm, ce.DueDate) AS Month,
COUNT(CASE WHEN rt.Code = 'Pass' THEN 1 ELSE NULL END) AS NumPass,
COUNT(CASE WHEN rt.Code = 'Fail' THEN 1 ELSE NULL END) AS NumFail
FROM
ControlEvent ce
INNER JOIN
ProcessEvent pe ON pe.ControlEventId = ce.Id
INNER JOIN
ResultType rt ON pe.ResultTypeId = rt.Id
WHERE
DATEDIFF(dd,ce.DueDate,GETDATE()) <= 0
AND DATEDIFF(dd,ce.DueDate,DATEADD(mm, 3, GETDATE())) >= 0
AND pe.ProcessId = 1040
GROUP BY
DATEPART(yyyy, ce.DueDate), DATEPART(mm, ce.DueDate)
ORDER BY
DATEPART(yyyy, ce.DueDate), DATEPART(mm, ce.DueDate)
到目前为止我已经这样做了
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();
我的问题是如何将我的 SQL 查询中的 case 语句带到 linq Select。谢谢
首先,删除 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
你快到了。就在您的 select 语句之前,您有一系列组,其中每个组都是一系列连接结果,其中每个连接结果具有相同的年份/月份。
例如,您有以下组
- group1(2015 年 1 月)= 截止日期为 2015 年 1 月的连接结果序列
- group2(2015 年 2 月)= 截止日期为 2015 年 2 月的连接结果序列
- group3(2015 年 2 月)= 截止日期为 2015 年 3 月的连接结果序列
您已经发现密钥中包含您想要的年份和月份。
对于 2015 年 1 月组的 NumPass,您需要 2015 年 1 月序列中匹配 joinResult.resultType.code == "Pass"、
的所有元素作为一个面向对象的程序员,我在写我的 Linq 语句时总是有点困难 SQL 这样的语法,所以如果你不介意的话,我用 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}
- 现在你有关键字为 {Year, Month} 的组。
- 每个组都有一系列具有属性 { Year, Month, ResultCode} 的对象
- 一组内的年/月都一样
现在您所要做的就是计算一组中匹配 "Pass" 和匹配 "Fail" 的所有元素:
继续 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();
这应该可以解决问题。
请注意,我将 ProcessId == 1048 的 Where 语句放在第二次加入之前,因为我猜这会限制要加入的项目数量。也许以下甚至会更聪明:
ControlEvents
.Where(controlEvent => controlEvent.DueDate >= startDate
&& controlEvent.DueDate <= endDate)
.Join (ProcessEvents.Where(processEvent => processEvent.Id == 1048),
key1 => etc,
我想这真的会限制加入的元素数量。
此外,请考虑在最终 select 之后按年/月排序,因为那样的话您还必须对更小的系列进行排序