0

我有我试图转换成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查询我的问题是如何能我把我的SQL查询中的case语句带到linq Select中。谢谢。

回答

1

首先,删除into resultType,因为它创建了一个组连接,并且您的SQL查询不使用这样的构造。

其次,在groupby之后移动orderby子句。

最后,使用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 
+0

什么,如果我想按年份,然后按周? Linq我怎么能做到这一点? – Ahsan

+0

没有标准的规范函数。如果您仅以SqlServer为目标,则可以使用[SqlFunctions.DatePart](https://msdn.microsoft.com/zh-cn/library/dd487171(v = vs.110).aspx) –

+0

做了一些更多的测试,结果发现成为sum语句正在带来ControlEvent.ResultTypes.Pass或Fail的总和,而我对ProcessEvent.ResultType.Pass或Fail感兴趣。对此有何想法? – Ahsan

0

你是几乎没有。在选择语句之前,您有一组组序列,其中每个组是一系列加入结果,其中每个加入结果具有相同的年/月。

因此,例如,您有以下组

  • 1组(2015年1月)=加入与交货期2015年1月
  • 组2的结果序列(2015年2月)=与交货期2015年2月
  • 加入结果的顺序
  • 第3组(2015年2月)=与交货期月加入结果的顺序2015年

你已经发现了钥匙包含一年你想要的月份。

对于2015年1月集团NumPass,你想匹配joinResult.resultType.code ==“通行证”是

2015年1月的序列中的所有元素,作为一个面向对象编程,我总是有一定的困难,现在你有一个键{年月}组

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语句的语法这一半SQL,因此,如果它不打扰你太多,我重写它使用lambda表达式。
  • 每个组都有对象具有属性{年,月,的ResultCode}
  • 在一组的年/月都是一样的

现在,所有你需要做的是计算中的所有元素的顺序

继续在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, 

我想这会真正限制要加入的元素的数量。

另外,考虑后最终选择以年/月订货,因为在这种情况下,你也可以选择订购了一个更小的集合

+0

count语句会带来ControlEvent.ResultTypes.Pass或Fail的总和,而我期待的是ProcessEvent.ResultType.Pass或Fail。对此有何看法? – Ahsan

+0

你写过“计数语句带来......的总和”。你确定?我真的认为Count()返回与where语句匹配的元素的数量。考虑使用Enumerable.Count(此源,Func )而不是where。您还写道:“我期待ProcessEvent.ResultType.Pass ...”您的SQL语句不会返回值ProcessEvent.ResultType,如果统计具有值“Pass”的ProcessEvents.ResultType的数量 –