我正在尝试使用过滤器编写EF查询,并且生成的SQL未在SQL Server上使用WHERE语句。它提取所有数据并在客户端内存上进行过滤。我非常担心性能,并希望在SQL Server上应用过滤器。
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:00
和07/04/2017 09:00
之间的记录数
计数确实返回6这是正确的,但是当我在SQL事件探查器中跟踪生成的SQL时,它会检索所有数据。
在SQL事件探查器中生成SQL
选择
[s]。[EnrolmentRecordID],[s]。[AF1],[s]。[AcademicYearID],[s]。[AdminName],[s]。[AppForm],[s]。[AppointmentDate], [s]。[AppointmentTime],[s]。[BDT],[s]。[BKSB],[s]。[DateCreated], [s]。[DateModified],[s]。[雇主],[s]。[EmployerInvited], [s]。[EmployerReps],[s]。[MIAPP],[s]。[NI],[s]。[ProposedQual], [s]。[SMT],[s]。[学生邀请],[s]。[学生姓名]这 [dbo]。[EN_Schedules] AS [s]
我想修改我的EF代码以生成WHERE语句并在服务器端执行过滤。我怎样才能实现它?
UPDATE1:
如果我删除了TimeSpan值的过滤器,它会生成正确的SQL语句,如下所示:所以,在我看来,我需要对TimeSpan Field应用不同的过滤器。
exec sp_executesql N&#39; SELECT COUNT(*)FROM [dbo]。[EN_Schedules] AS [s] WHERE([s]。[state] = 0)AND(CONVERT(date,[s]。[AppointmentDate])= @__ dt_Date_0)&#39;,N&#39; @__ dt_Date_0 datetime2(7)&#39;,@ __ dt_Date_0 =&#39; 2017-04-07 00:00:00&#39;
** Update2:**
通过使用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
);
答案 0 :(得分:3)
它确实转换为客户评估 - 看起来EF Core仍然不支持许多TimeSpan
操作。
经过大量的反复试验,目前唯一可以将其转换为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
);
答案 1 :(得分:1)
看起来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));
}
}