我已经对此做了一些研究,到目前为止我发现的最好的是在整个数据集上使用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)
};
这给了我几个月的YYYY-MM格式,以及总金额和平均金额。但是每次都需要几分钟。
我的其他解决方法是在SQL中执行更新查询,因此我有一个YYYYMM字段可以本机分组。更改数据库不是一个简单的解决方案,因此任何建议都将受到赞赏。
我找到上述代码构思的线程(http://stackoverflow.com/questions/1059737/group-by-weeks-in-linq-to-entities)提到'等到.NET 4.0'。最近有什么介绍有助于这种情况吗?
答案 0 :(得分: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
});
修改强> 的
我的响应中的原始查询试图在int和字符串之间进行连接,而EF不能将其转换为SQL语句。我可以使用 SqlFunctions 类,但它变得有点难看。所以我在分组后添加 AsEnumerable () ,这意味着EF将在服务器上执行组查询,将获得年,月等,但是自定义投影是在对象上进行的(在 AsEnumerable ()之后的内容。)
答案 1 :(得分:9)
说到逐个月,我更喜欢这样做:
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
})
因为它将日期时间类型保留在分组结果中。
答案 2 :(得分:2)
与cryss写的相似,我正在为EF做以下事情。请注意,我们必须使用EntityFunction来调用EF支持的所有数据库提供程序。 SqlFunctions仅适用于SQLServer。
var sqlMinDate = (DateTime) SqlDateTime.MinValue;
(from x in ExpenseItemsViewableDirect
let month = EntityFunctions.AddMonths(sqlMinDate, EntityFunctions.DiffMonths(sqlMinDate, x.Er_Approved_Date))
group d by month
into g
select new
{
Period = g.Key,
Total = g.Sum(x => x.Item_Amount),
AveragePerTrans = Math.Round(g.Average(x => x.Item_Amount),2)
}).Dump();
尝试生成SQL(来自类似架构):
-- Region Parameters
DECLARE @p__linq__0 DateTime2 = '1753-01-01 00:00:00.0000000'
DECLARE @p__linq__1 DateTime2 = '1753-01-01 00:00:00.0000000'
-- EndRegion
SELECT
1 AS [C1],
[GroupBy1].[K1] AS [C2],
[GroupBy1].[A1] AS [C3]
FROM ( SELECT
[Project1].[C1] AS [K1],
FROM ( SELECT
DATEADD (month, DATEDIFF (month, @p__linq__1, [Extent1].[CreationDate]), @p__linq__0) AS [C1]
FROM [YourTable] AS [Extent1]
) AS [Project1]
GROUP BY [Project1].[C1]
) AS [GroupBy1]