Как выполнить этот запрос сравнения вложенных дат EF Core в SQL - PullRequest
0 голосов
/ 28 сентября 2018

Использование .Net Core 2.1 и EF Core 2.1.1 и SQL Server

Я пытаюсь получить список Organizations и их список Communications
Затем я хочу ограничить егодля тех, у кого не было Communications за последние 6 месяцев

Вот мои уменьшенные ViewModels:

public class OrganizationViewModel
{
    public Guid Id { get; set; }
    public IEnumerable<CommunicationViewModel> CommunicationViewModels { get; set;
}

public class CommunicationViewModel
{
    public Guid Id { get; set; }
    public DateTime Date { get; set; }

    public Guid OrganizationViewModelId { get; set; }
    public OrganizationViewModel OrganizationViewModel { get; set; }
}

А вот мой запрос:

DateTime sixMonthsAgo = DateTime.Today.AddMonths(-6);
int pageIndex = 1; // Would be passed in
int pageSize = 3;

IQueryable<OrganizationViewModel> query = _context.Organizations
    .AsNoTracking()
    .Select(organization => new OrganizationViewModel
    {
        CommunicationViewModels = organization.Communications.Select(communication => new CommunicationViewModel
        {
            Date = communication.Date
        })              
        .OrderByDescending(communication => communication.Date)
        .Take(1)
        .ToList()
    })
    .Where(organization => 
        (!searchViewModel.LimitToLastSixMonths || 
            organization.CommunicationViewModels.Any(communication => communication.Date <= sixMonthsAgo)));

int totalAmount = await query.CountAsync();
List<OrganizationViewModel> items = await query
            .Skip((pageIndex - 1) * pageSize)
            .Take(pageSize)
            .ToListAsync();

Это дает мне ожидаемые результаты, но я вижу в своих журналах, что я выполняю этот запрос для каждой записи, когда нажимаю .CountAsync() и. Skip(..).Take(..):

SELECT CASE
    WHEN EXISTS (
        SELECT 1
        FROM (
            SELECT TOP(1) [comm].[Date]
            FROM [Communications] AS [comm]
            WHERE @_outer_Id = [comm].[OrganizationId]
            ORDER BY [comm].[Date] DESC
        ) AS [t]
        WHERE [t].[Date] <= @__sixMonthsAgo_0)
    THEN CAST(1 AS BIT) ELSE CAST(0 AS BIT)
END

Ятакже видит эти предупреждения при вызове .CountAsync() (слегка отредактированный):

Microsoft.EntityFrameworkCore.Query: Предупреждение: выражение LINQ
'where (False OrElse {from CommunicationViewModel cvm in {from Communication comm in value(..EntityQueryable'1[..Models.Communication]) orderby [comm].Date desc where ?= (Property([o], "Id") == Property([comm], "OrganizationId")) =? select new CommunicationViewModel() {Date = [comm].Date} => Take(1) => AsQueryable()} where ([cvm].Date <= __sixMonthsAgo_0) select [cvm] => Any()})' не может быть переведено и будет оценено локально.
Microsoft.EntityFrameworkCore.Query: Предупреждение: выражение LINQ 'Count ()' не может быть переведено и будет оценено локально.

И подобные ошибки при вызове .Take(..).Skip(..):

Microsoft.EntityFrameworkCore.Query: Предупреждение: выражение LINQ
same as above не может быть переведено и будет оцениваться локально.Microsoft.EntityFrameworkCore.Query: Предупреждение: выражение LINQ «Пропустить (__ p_1)» не может быть переведено и будет оценено локально.
Microsoft.EntityFrameworkCore.Query: Предупреждение: выражение LINQ «Take (__ p_2)» не может бытьпереведен и будет оцениваться локально.

Этого не происходит, если searchViewModel.LimitToLastSixMonths ложно

Любые предложения о том, как я могу переписать свой запрос, чтобы не выполнять этот запрос локально для каждой записи

Ответы [ 2 ]

0 голосов
/ 01 октября 2018

Я понял!

Это мой новый запрос:

DateTime sixMonthsAgo = DateTime.Today.AddMonths(-6);
int pageIndex = 1; // Would be passed in
int pageSize = 3;

IQueryable<OrganizationViewModel> query = _context.Organizations
    .AsNoTracking()
    .Select(organization => new OrganizationViewModel
    {
        CommunicationViewModels = organization.Communications.Select(communication  => 
            new CommunicationViewModel
            {
                Id = communication.Id,
                Date = communication.Date
            })
            .OrderByDescending(communicationViewModel => communicationViewModel.Date)
            .Take(1)
            .Where(communicationViewModel => communicationViewModel.Date <= sixMonthsAgo)
            .AsQueryable()
    })
    .Where(organizationViewModel =>
        (!searchViewModel.LimitToLastSixMonths || organizationViewModel.CommunicationViewModels.Any()));

int totalAmount = await query.CountAsync();
List<OrganizationViewModel> items = await query
            .Skip((pageIndex - 1) * pageSize)
            .Take(pageSize)
            .ToListAsync();

, который теперь выдает эти два запроса, когда searchViewModel.LimitToLastSizeMonths равен true:

SELECT COUNT(*)
FROM [Organizations] AS [organization]
WHERE EXISTS (
    SELECT 1
    FROM (
        SELECT [t].[Id], [t].[Date]
        FROM (
            SELECT TOP(1) [communication].[Id], [communication].[Date]
            FROM [Communications] AS [communication]
            WHERE [organization].[Id] = [communication].[OrganizationId]
            ORDER BY [communication].[Date] DESC
        ) AS [t]
        WHERE [t].[Date] <= @__sixMonthsAgo_0
    ) AS [t0])


SELECT [organization].[Id]
FROM [Organizations] AS [organization]
WHERE EXISTS (
    SELECT 1
    FROM (
        SELECT [t].[Id], [t].[Date]
        FROM (
            SELECT TOP(1) [communication].[Id], [communication].[Date]
            FROM [Communications] AS [communication]
            WHERE [organization].[Id] = [communication].[OrganizationId]
            ORDER BY [communication].[Date] DESC
        ) AS [t]
        WHERE [t].[Date] <= @__sixMonthsAgo_0
    ) AS [t0])
ORDER BY (SELECT 1)
OFFSET @__p_1 ROWS FETCH NEXT @__p_2 ROWS ONLY

Без .AsQueryable() возвращается к проверке каждой записи и выполнению подсчета и катанию на лыжах / заборе на месте.

0 голосов
/ 29 сентября 2018

Что если вы попытаетесь включить свойство навигации в select:

IQueryable<OrganizationViewModel> query = _context.Organizations
    .Include(o => o.CommunicationViewModels)
...
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...