【问题标题】:How can I generate SQL with WHERE statement in EFCore Query如何在 EFCore 查询中使用 WHERE 语句生成 SQL
【发布时间】:2017-04-28 03:42:55
【问题描述】:

我正在尝试使用过滤器编写 EF 查询,并且生成的 SQL 未在 SQL Server 上使用 WHERE 语句。它提取所有数据并对客户端的内存进行过滤。我很担心性能,想在 SQL Server 上应用过滤器。

要求是统计一个Hour时间段的记录数。

public async Task<int> GetNumberofSchedules(DateTime dt)
{
    return await _context.Schedules.CountAsync(
        s => s.state == 0
                && s.AppointmentDate.Value.Date == dt.Date
                && s.AppointmentTime.Value.Hours >= dt.Hour
                && s.AppointmentTime.Value.Hours < dt.AddHours(1).Hour
        );
}

样本数据

如果给定的 DateTime 是07/04/2017 08:20,它应该返回07/04/2017 08:0007/04/2017 09:00 之间的记录数

计数确实返回 6,这是正确的,但是当我在 SQL Profiler 中跟踪生成的 SQL 时,它正在检索所有数据。

在 SQL Profiler 中生成的 SQL

选择
[s].[EnrolmentRecordID], [s].[AF1], [s].[AcademicYearID], [s].[AdminName], [s].[AppForm], [s].[AppointmentDate], [s].[AppointmentTime], [s].[BDT], [s].[BKSB], [s].[DateCreated], [s].[DateModified], [s].[Employer], [s].[EmployerInvited], [s].[EmployerReps], [s].[MIAPP], [s].[NI], [s].[ProposedQual], [s].[SMT]、[s].[StudentInvited]、[s].[StudentName]

来自 [dbo].[EN_Schedules] AS [s]

我想修改我的 EF 代码以生成 WHERE 语句并在服务器端进行过滤。我怎样才能实现它?

更新1:

如果我删除 TimeSpan 值的过滤器,它会生成正确的 SQL 语句,如下所示:因此,在我看来,我需要为 TimeSpan 字段应用不同的过滤器。

exec sp_executesql N'SELECT COUNT(*) FROM [dbo].[EN_Schedules] AS [s] WHERE ([s].[state] = 0) AND (CONVERT(date, [s].[AppointmentDate]) = @__dt_Date_0)',N'@__dt_Date_0 datetime2(7)',@__dt_Date_0='2017-04-07 00:00:00'

**更新2:**

通过使用 Ivan 的解决方案,我最终这样做了:

var startTime = new TimeSpan(dt.Hour, 0, 0);
var endTime = new TimeSpan(dt.Hour + 1, 0, 0);

return await _context.Schedules.CountAsync(
     s => s.state == 0
          && s.AppointmentDate.Value.Date == dt.Date
          && s.AppointmentTime.Value >= startTime
          && s.AppointmentTime.Value < endTime

 );

【问题讨论】:

    标签: entity-framework entity-framework-core


    【解决方案1】:

    它确实已转换为客户端评估 - 看起来许多 TimeSpan 操作仍然不能被 EF Core 很好地支持。

    经过大量试验和错误,目前您可以将其转换为 SQL 的唯一方法是将 TimeSpan 限制准备为变量并在查询中使用它们:

    var startTime = new TimeSpan(dt.Hour, 0, 0);
    var endTime = startTime + new TimeSpan(1, 0, 0);
    
    return await _context.Schedules.CountAsync(
        s => s.state == 0
            && s.AppointmentDate.Value.Date == dt.Date
            && s.AppointmentTime.Value >= startTime
            && s.AppointmentTime.Value < endTime
    );
    

    【讨论】:

      【解决方案2】:

      看起来Client Evaluation是原因。

      通过ConfigureWarnings 调用禁用它。如果无法将 LINQ 语句转换为 SQL,则会出现异常:

      public class FooContext : DbContext
      {
          protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
          {
              optionsBuilder
                  .UseSqlServer("foo_connstr")
                  .ConfigureWarnings(warnings => warnings.Throw(RelationalEventId.QueryClientEvaluationWarning));
          }
      }
      

      【讨论】:

      猜你喜欢
      • 2015-07-25
      • 1970-01-01
      • 1970-01-01
      • 2017-09-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-12-02
      • 2014-10-13
      相关资源
      最近更新 更多