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的數量 –