在LINQ to Entities中按週分組

c# entity-framework linq linq-to-entities

我有一個應用程序,允許用戶輸入他們工作的時間,我正在嘗試為此構建一個良好的報告,利用LINQ to Entities。因為每個TrackedTime都有一個TargetDate ,它只是DateTime的“Date”部分,所以按用戶和日期對時間進行分組相對簡單(為簡單起見,我省略了“where”子句):

var userTimes = from t in context.TrackedTimes
                group t by new {t.User.UserName, t.TargetDate} into ut
                select new
                {
                    UserName = ut.Key.UserName,
                    TargetDate = ut.Key.TargetDate,
                    Minutes = ut.Sum(t => t.Minutes)
                };

由於DateTime.Month屬性,按用戶和Month分組只是稍微複雜一些:

var userTimes = from t in context.TrackedTimes
                group t by new {t.User.UserName, t.TargetDate.Month} into ut
                select new
                {
                    UserName = ut.Key.UserName,
                    MonthNumber = ut.Key.Month,
                    Minutes = ut.Sum(t => t.Minutes)
                };

現在是棘手的部分。是否有可靠的方式按週分組?我根據對類似LINQ to SQL問題的響應嘗試了以下內容:

DateTime firstDay = GetFirstDayOfFirstWeekOfYear();
var userTimes = from t in context.TrackedTimes
                group t by new {t.User.UserName, WeekNumber = (t.TargetDate - firstDay).Days / 7} into ut
                select new
                {
                    UserName = ut.Key.UserName,
                    WeekNumber = ut.Key.WeekNumber,
                    Minutes = ut.Sum(t => t.Minutes)
                };

但LINQ to Entities似乎不支持DateTime對像上的算術運算,因此它不知道該怎麼做(t.TargetDate - firstDay).Days / 7

我考慮在數據庫中創建一個只需幾天到幾週的視圖,然後將該視圖添加到我的實體框架上下文並在我的LINQ查詢中加入它,但這似乎是很多工作。算術方法有一個很好的解決方法嗎?與Linq to Entities一起使用的東西,我可以簡單地將其合併到LINQ語句中而無需觸及數據庫?某種方式告訴Linq實體如何從另一個中減去一個日期?

摘要

我要感謝大家的深思熟慮和創造性的回應。在所有這些來回之後,看起來這個問題的真正答案是“等到.NET 4.0。”我將向Noldorin提供獎勵,以提供仍然利用LINQ的最實用的答案,特別提到Jacob Proffitt提出的使用實體框架的響應,而無需在數據庫端進行修改。還有其他很好的答案,如果你是第一次看到這個問題,我強烈建議你閱讀所有已被投票的人,以及他們的評論。這確實是StackOverflow功能的極好例子。謝謝你們!

一般承認的答案

您應該能夠使用對AsEnumerable擴展方法的調用來強制查詢使用LINQ to Objects而不是LINQ to Entities進行分組。

請嘗試以下方法:

DateTime firstDay = GetFirstDayOfFirstWeekOfYear();
var userTimes = 
    from t in context.TrackedTimes.Where(myPredicateHere).AsEnumerable()
    group t by new {t.User.UserName, WeekNumber = (t.TargetDate - firstDay).Days / 7} into ut
    select new
    {
        UserName = ut.Key.UserName,
        WeekNumber = ut.Key.WeekNumber,
        Minutes = ut.Sum(t => t.Minutes)
    };

這至少意味著where子句由LINQ to Entities執行,但是對於實體來說太複雜的group子句由LINQ to Objects完成。

如果你對此有任何好運,請告訴我。

更新

這是另一個建議,它可能允許您使用LINQ to Entities來完成整個事情。

(t.TargetDate.Days - firstDay.Days) / 7

這只是擴展了操作,因此只執行整數減法而不是DateTime減法。

它目前尚未經過測試,因此它可能有效也可能無效......


熱門答案

只要您使用SQLServer,您也可以在LINQ中使用SQL函數:

using System.Data.Objects.SqlClient;

var codes = (from c in _twsEntities.PromoHistory
                         where (c.UserId == userId)
                         group c by SqlFunctions.DatePart("wk", c.DateAdded) into g
                         let MaxDate = g.Max(c => SqlFunctions.DatePart("wk",c.DateAdded))
                         let Count = g.Count()
                         orderby MaxDate
                         select new { g.Key, MaxDate, Count }).ToList();

此示例改編自MVP Zeeshan Hirani在此主題: MSDN



許可下: CC-BY-SA with attribution
不隸屬於 Stack Overflow
這個KB合法嗎? 是的,了解原因
許可下: CC-BY-SA with attribution
不隸屬於 Stack Overflow
這個KB合法嗎? 是的,了解原因