【问题标题】:How to perform this EF Core nested date comparison query in SQL如何在 SQL 中执行此 EF Core 嵌套日期比较查询
【发布时间】:2018-09-28 16:53:38
【问题描述】:

使用 .Net Core 2.1 和 EF Core 2.1.1 和 SQL Server

我正在尝试提取Organizations 的列表及其Communications 的列表
然后,我想将其限制在过去 6 个月内没有任何 Communications 的用户

这是我略读的 ViewModel:

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} =&gt; Take(1) =&gt; AsQueryable()} where ([cvm].Date &lt;= __sixMonthsAgo_0) select [cvm] =&gt; Any()})' 无法翻译,将在本地进行评估。
Microsoft.EntityFrameworkCore.Query:警告:无法翻译 LINQ 表达式“Count()”,将在本地计算。

在调用.Take(..).Skip(..) 时出现类似错误:

Microsoft.EntityFrameworkCore.Query:Warning:LINQ 表达式
same as above 无法翻译,将在本地进行评估。 Microsoft.EntityFrameworkCore.Query:警告:无法翻译 LINQ 表达式“Skip(__p_1)”,将在本地进行评估。
Microsoft.EntityFrameworkCore.Query:警告:无法翻译 LINQ 表达式“Take(__p_2)”,将在本地进行评估。

searchViewModel.LimitToLastSixMonths 为假时不会发生这种情况

关于如何重写查询以不在每条记录上本地执行该查询的任何建议?

【问题讨论】:

    标签: c# sql-server linq asp.net-core entity-framework-core


    【解决方案1】:

    如果您尝试将导航属性包含在选择中会怎样:

    IQueryable<OrganizationViewModel> query = _context.Organizations
        .Include(o => o.CommunicationViewModels)
    ...
    

    【讨论】:

    • 抱歉回复晚了,周末无法访问我的代码。添加Include 语句不会更改结果。 EF 告诉我它忽略了它:Microsoft.EntityFrameworkCore.Query:Warning: The Include operation for navigation '[o].Communications' is unnecessary and was ignored because the navigation is not reachable in the final query results.
    【解决方案2】:

    我想通了!

    这是我的新查询:

    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.LimitToLastSizeMonthstrue 时,现在会产生这两个查询:

    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(),它会返回检查每条记录并在本地执行计数和滑雪/拍摄。

    【讨论】:

      猜你喜欢
      • 2010-11-08
      • 1970-01-01
      • 2023-03-19
      • 2023-03-15
      • 2013-11-24
      • 1970-01-01
      • 2013-09-16
      • 2012-08-02
      • 1970-01-01
      相关资源
      最近更新 更多