问题
Below is my SQL query that I'm looking to convert to LINQ query
SELECT
ProcessName,
SUM(CASE WHEN Status = 'In-Progress' THEN 1 ELSE 0 END) As 'In-Progress',
SUM(CASE WHEN Status = 'Success' THEN 1 ELSE 0 END) As 'Completed',
Count(CASE WHEN status in ('In-Progress','Success') then 1 end) as Total
FROM
TableName
GROUP BY
ProcessName
回答1:
The first part is easy. The SQL expression SUM(CASE WHEN condition THEN 1 ELSE 0 END)
directly maps to the LINQ Sum(condition ? 1 : 0)
.
More interesting is the SQL expression COUNT(CASE WHEN condition THEN 1 END
. It's a shortcut for COUNT(CASE WHEN condition THEN 1 ELSE NULL END
. Now, taking into account that SQL COUNT
function skips the NULL values, the LINQ mapping could be either Count(condition)
or Sum(condition ? 1 : 0)
. From my experience with EF, the later translates to a better SQL (the former generates additional subquery reading from the source table), so I always prefer it in LINQ to Entities queries.
With that being said, the LINQ query could be something like this:
// constants to avoid typos
const string StatusInProgress = "In-Progress";
const string StatusCompleted = "Success";
// needed for IN clause
var statuses = new[] { StatusInProgress, StatusCompleted };
// the query
var query =
from e in db.TableA
group e by e.ProcessName into g
select new
{
InProgress = g.Sum(e => e.Status == StatusInProgress ? 1 : 0),
Completed = g.Sum(e => e.Status == StatusCompleted ? 1 : 0),
C = g.Sum(e => statuses.Contains(e.Status) ? 1 : 0),
};
and the generated SQL looks like this:
SELECT
1 AS [C1],
[GroupBy1].[K1] AS [ProcessName],
[GroupBy1].[A1] AS [C2],
[GroupBy1].[A2] AS [C3],
[GroupBy1].[A3] AS [C4]
FROM ( SELECT
[Extent1].[K1] AS [K1],
SUM([Extent1].[A1]) AS [A1],
SUM([Extent1].[A2]) AS [A2],
SUM([Extent1].[A3]) AS [A3]
FROM ( SELECT
[Extent1].[ProcessName] AS [K1],
CASE WHEN (N'In-Progress' = [Extent1].[Status]) THEN 1 ELSE 0 END AS [A1],
CASE WHEN (N'Success' = [Extent1].[Status]) THEN 1 ELSE 0 END AS [A2],
CASE WHEN ([Extent1].[Status] IN (N'In-Progress', N'Success')) THEN 1 ELSE 0 END AS [A3]
FROM [dbo].[TableName] AS [Extent1]
) AS [Extent1]
GROUP BY [K1]
) AS [GroupBy1]
As you can see, except the ugly outer parts that do nothing, the main part contained in the innermost subquery is almost identical to the SQL query in question.
回答2:
You may do something like that :
var statuses = new {"In-Progress","Success"};
var res = yourData
.GroupBy(m => m.ProcessName)
.Select(g => new {
ProcessName = g.Key,
//for InProgress, 2 (or 3) ways
InProgress = g.Select(x => x.Status == "In-Progress" ? 1 : 0).Sum(),
//another way
InProgress = g.Where(x => x.Status == "In-Progress").Count(),
//another way, not sure if it works in linq to entities
InProgress = g.Count(x => x.Status == "In-Progress"),
//same 3 ways possible for completed, the first here
Completed = g.Select(x => x.status == "Success" ? 1 : 0).Sum(),
//for the count
//not sure if this one works in linq to entities
Total = g.Count(x => statuses.Contains(x.Status))
//alternative
Total = g.Where(x => statuses.Contains(x.Status)).Count()
});
回答3:
string statuses = new {"In-Progress","Success"};
var results = from item in TableName
group item by p.ProcessName into g
select new yourReturnType
{
ProcessName = g.Key,
In-Progress = g.Where(l=>l.Status == "In-Progress").Count(),
Completed = g.Where(l=>l.Status == "Success").Count(),
Total = g.Where(x => statuses.Contains(x.Status)).Count()
};
来源:https://stackoverflow.com/questions/39590025/convert-sumcase-sql-statement-to-linq-query-in-entity-framework