实体框架:按月进行有效分组

Gli*_*kot 11 .net c# entity-framework

我已经对此做了一些研究,到目前为止我发现的最好的是在整个数据集中使用Asenumerable,以便过滤发生在对象而不是数据库中.我正在使用最新的EF.

我的工作(但很慢)代码是:

        var trendData = 
            from d in ExpenseItemsViewableDirect.AsEnumerable()
            group d by new {Period = d.Er_Approved_Date.Year.ToString() + "-" + d.Er_Approved_Date.Month.ToString("00") } into g
            select new
            {
                Period = g.Key.Period,
                Total = g.Sum(x => x.Item_Amount),
                AveragePerTrans = Math.Round(g.Average(x => x.Item_Amount),2)
            };
Run Code Online (Sandbox Code Playgroud)

这给了我几个月的YYYY-MM格式,以及总金额和平均金额.但是每次都需要几分钟.

我的另一个解决方法是在SQL中执行更新查询,因此我有一个YYYYMM字段可以本地分组.更改数据库不是一个简单的解决方案,因此任何建议将不胜感激.

我找到上述代码构思的线程(http://stackoverflow.com/questions/1059737/group-by-weeks-in-linq-to-entities)提到'等到.NET 4.0'.最近有什么介绍有助于这种情况吗?

Adr*_*ode 16

性能不佳的原因是整个表被提取到内存中(AsEnumerable()).您可以像这样按年和月分组

var trendData = 
            (from d in ExpenseItemsViewableDirect
            group d by new {
                            Year = d.Er_Approved_Date.Year, 
                            Month = d.Er_Approved_Date.Month 
                            } into g
            select new
            {
                Year = g.Key.Year,
                Month = g.Key.Month,
                Total = g.Sum(x => x.Item_Amount),
                AveragePerTrans = Math.Round(g.Average(x => x.Item_Amount),2)
            }
       ).AsEnumerable()
        .Select(g=>new {
              Period = g.Year + "-" + g.Month,
              Total = g.Total,
               AveragePerTrans = g.AveragePerTrans
         });
Run Code Online (Sandbox Code Playgroud)

编辑

我的响应中的原始查询试图在int和字符串之间进行连接,而EF不能将其转换为SQL语句.我可以使用SqlFunctions类,但查询它变得有点难看.所以我在分组之后添加了AsEnumerable(),这意味着EF将在服务器上执行组查询,将获得年,月等,但是自定义投影是在对象上进行的(在AsEnumerable()之后是什么).


cry*_*yss 10

说到逐月,我更喜欢以这种方式完成这项任务:

var sqlMinDate = (DateTime) SqlDateTime.MinValue;

var trendData = ExpenseItemsViewableDirect
    .GroupBy(x => SqlFunctions.DateAdd("month", SqlFunctions.DateDiff("month", sqlMinDate, x.Er_Approved_Date), sqlMinDate))
    .Select(x => new
    {
        Period = g.Key // DateTime type
    })
Run Code Online (Sandbox Code Playgroud)

因为它将日期时间类型保留在分组结果中.