linq - EFCore 2.2 GroupBy Sum 和 DateDiff

标签 linq group-by linq-to-entities datediff ef-core-2.2

我正在尝试将以下 SQL 转换为 EF Core 查询,但我收到警告,将在本地评估 GroupBy 和 Sum。无论如何,目前是否可以编写此内容以将其完全转换为 SQL?

SELECT UserId, ST.StatusId, SUM(DATEDIFF(MINUTE, StartDate, ISNULL(EndDate,GETDATE()))) AS Time
FROM StatusTransaction ST
WHERE
    TeamManagerId = 1
    AND StartDate >= N'01-01-2019'
    AND ISNULL(EndDate,GETDATE()) <= N'01-02-2019'
GROUP BY UserId, ST.StatusId
ORDER BY UserId

这些是我使用过的 EF 查询:
var efFunction = await context
    .Where(st => st.TeamManagerId == tmId && st.StartDate >= dateFrom && (st.EndDate ?? DateTime.Now) <= dateTo)
    .GroupBy(st => new { st.UserId, st.StatusId })
    .Select(g => new
        {
            g.Key.UserId,
            g.Key.StatusId,
            Time = g.Sum(st => Microsoft.EntityFrameworkCore.EF.Functions.DateDiffMinute(st.StartDate, st.EndDate)) // null check not done on end date - (st.EndDate ?? DateTime.Now) causes an error here
        }).ToListAsync(cancellationToken).ConfigureAwait(false);

var simpleDateSubtraction = await context
    .Where(st => st.TeamManagerId == tmId && st.StartDate >= dateFrom && (st.EndDate ?? DateTime.Now) <= dateTo)
    .GroupBy(st => new { st.UserId, st.StatusId })
    .Select(g => new
    {
        g.Key.UserId,
        g.Key.StatusId,
        Time = g.Sum(st => st.EndDate.Value.Subtract(st.StartDate).Minutes)// null check not done on end date - (st.EndDate ?? DateTime.Now) causes an error here
    }).ToListAsync(cancellationToken).ConfigureAwait(false);

var groupBySimpleSum = await context
    .Where(st => st.TeamManagerId == tmId)
    .GroupBy(st => new { st.TeamManagerId, st.OperationsManagerId })
    .Select(g => new
    {
        g.Key.OperationsManagerId,
        g.Key.TeamManagerId,
        Foo = g.Sum(st => st.UserId) // nonsense but a simple column to sum, this translates fully to SQL
    }).ToListAsync(cancellationToken).ConfigureAwait(false);

最佳答案

首先,EF Core 仍然不支持翻译 TimeSpan操作,和 DateTime差异产生TimeSpan ,因此 EF.Functions.DateDiff方法是正确的方法。

其次,它还可以翻译GroupBy仅在简单的成员访问器表达式上聚合。所以你必须预先Select GroupBy表达式:

var query = context
    .Where(st => st.TeamManagerId == tmId
        && st.StartDate >= dateFrom
        && (st.EndDate ?? DateTime.Now) <= dateTo
    )
    .Select(st => new
    {
        st.UserId,
        st.StatusId,
        Time = EF.Functions.DateDiffMinute(st.StartDate, st.EndDate ?? DateTime.Now)
    })
    .GroupBy(st => new { st.UserId, st.StatusId })
    .Select(g => new
    {
        g.Key.UserId,
        g.Key.StatusId,
        Time = g.Sum(st => st.Time)
    });

或使用 GroupBy允许预先选择聚合源的重载:
var query = context
    .Where(st => st.TeamManagerId == tmId
        && st.StartDate >= dateFrom
        && (st.EndDate ?? DateTime.Now) <= dateTo
    )
    .GroupBy(st => new { st.UserId, st.StatusId }, st => new
    {
        Time = EF.Functions.DateDiffMinute(st.StartDate, st.EndDate ?? DateTime.Now)
    })
    .Select(g => new
    {
        g.Key.UserId,
        g.Key.StatusId,
        Time = g.Sum(st => st.Time)
    });

关于linq - EFCore 2.2 GroupBy Sum 和 DateDiff,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54670684/

相关文章:

c# - 为什么将 OrderBy 添加到 LINQ to EF 查询可以提高其性能?

linq - 执行 Linq to Sitecore 查询时获取 Stack Overflow

多对多 EF Code First 对象中带有 where 子句的 Linq

linq - 仅将日期的年份部分用于 WHERE 条件

mysql - 按列分组后获取mysql中最大的年份值

sql - GROUP BY 在 SQL 中使用参数

c# - 比较前删除字符串中的空格

c# - 选择列表中的项目时如何将属性值设置为 null

python - pandas - 创建客户移动矩阵

.net - 单个Linq-to-Entities查询中的多个SQL聚合函数