如何在LINQ的where条件中去除可空DateTime的时间部分并解决翻译报错
解决方案
报错原因
ToShortDateString()是C#原生的字符串转换方法,Entity Framework 无法将该方法翻译为对应的SQL语句在数据库侧执行,因此抛出无法翻译的异常。
可行方案
方案1:使用Date属性比较(适合EF Core 3.0+版本,写法最简单)
EF Core 原生支持DateTime.Date属性的SQL翻译,可直接提取日期部分比较,注意可空类型需要先判断是否有值:
public ICollection<Attendance> GetClockList(string code, DateTime datefrom) { ICollection<Attendance> data = new List<Attendance>(); data = (from log in ctx.Attendance join emp in ctx.Employee on log.EmpCode equals emp.EmployeeID.ToString() where log.EmpCode == empcode // 新增非空判断,避免空值报错,且空值天然不匹配日期条件 && log.ClockedDate.HasValue // 直接取Date属性比较日期部分,EF Core可自动翻译 && log.ClockedDate.Value.Date == datefrom.Date select new Attendance { EmployeeName = emp.EmployeeName, ClockedDate = log.ClockedDate, } ).ToList(); return data; }
方案2:日期区间比较法(全EF版本兼容,性能最优)
提前计算目标日期的起止时间范围,直接判断打卡时间落在该区间内,该写法翻译后的SQL为普通的范围查询,可命中ClockedDate字段的索引,性能远高于函数转换后比较,且无需处理可空类型的Value调用:
public ICollection<Attendance> GetClockList(string code, DateTime datefrom) { ICollection<Attendance> data = new List<Attendance>(); // 提前计算日期范围:目标日期的0点到次日0点 DateTime startOfDay = datefrom.Date; DateTime endOfDay = startOfDay.AddDays(1); data = (from log in ctx.Attendance join emp in ctx.Employee on log.EmpCode equals emp.EmployeeID.ToString() where log.EmpCode == empcode // 直接范围比较,可空类型为null时自动不满足条件,无需额外判断 && log.ClockedDate >= startOfDay && log.ClockedDate < endOfDay select new Attendance { EmployeeName = emp.EmployeeName, ClockedDate = log.ClockedDate, } ).ToList(); return data; }
不推荐做法
不要通过提前调用AsEnumerable()/ToList()把全表数据拉到内存后再过滤,数据量较大时会产生严重的性能问题。
内容的提问来源于stack exchange,提问作者Alan Pauil
相关产品推荐
相关产品推荐

