EFCore 2.2 GroupBy Sum и DateDiff - PullRequest
       17

EFCore 2.2 GroupBy Sum и DateDiff

0 голосов
/ 13 февраля 2019

Я пытаюсь перевести следующий 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);

1 Ответ

0 голосов
/ 17 февраля 2019

Во-первых, 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)
    });
...