EF Core 6过滤查询出现「Data is Null」错误的排查求助
问题原因
你的实体类tblAttendance中,LogoutDate和LogoutTime被定义为非可空值类型(DateTime、TimeSpan),但数据库中存在LogoutTime为NULL的记录(比如样本数据里ID为724075的行)。
- 全量查询时你通过
Select映射到AttendanceData,推测AttendanceData中对应的字段是可空类型,因此能正常处理NULL值; - 当直接查询实体
tblAttendance(不管是LINQ过滤还是FromSqlRaw)时,EF Core无法将数据库的NULL值赋值给非可空的实体属性,从而抛出「Data is Null」错误。
解决方案
1. 修正实体类的可空性(最根本的解决方式)
将数据库中允许为NULL的字段,在实体类中改为可空值类型:
public partial class tblAttendance { public long id { get; set; } public string? UserName { get; set; } public DateTime LoginDate { get; set; } public TimeSpan LoginTime { get; set; } public DateTime? LogoutDate { get; set; } // 改为可空 public TimeSpan? LogoutTime { get; set; } // 改为可空 public string? ComputerName { get; set; } public string? LogonServer { get; set; } }
2. 在查询中处理NULL值(不修改实体类的情况下)
如果暂时不想修改实体类,可以在SQL查询中给NULL字段设置默认值,避免EF Core转换失败:
SELECT id, UserName, LoginDate, LoginTime, ISNULL(LogoutDate, '1900-01-01') AS LogoutDate, ISNULL(LogoutTime, '00:00:00') AS LogoutTime, ComputerName, LogonServer FROM tblAttendance WHERE DATEPART(year, loginDate) = 2023 AND DATEPART(month, loginDate) = 6
3. 使用EF Core LINQ查询替代拼接SQL(更安全,避免注入)
推荐用LINQ构建查询,既安全又能统一处理NULL值:
var query = dbContext.tblAttendances.AsQueryable(); // 添加过滤条件 if (!string.IsNullOrEmpty(userName)) { query = query.Where(a => a.UserName == userName); } if (!string.IsNullOrEmpty(computerName)) { query = query.Where(a => a.ComputerName == computerName); } if (loginDate.Ticks > 0) { query = query.Where(a => a.LoginDate.Year == loginDate.Year && a.LoginDate.Month == loginDate.Month); } // 映射到AttendanceData并处理NULL var results = query.Select(a => new AttendanceData { UserName = a.UserName ?? "", LoginDate = a.LoginDate, LoginTime = a.LoginTime, LogoutDate = a.LogoutDate ?? DateTime.MinValue, // 可根据业务需求调整默认值 LogoutTime = a.LogoutTime ?? TimeSpan.Zero, ComputerName = a.ComputerName ?? "", LogonServer = a.LogonServer ?? "" }).ToList();
4. 修复SQL拼接的安全问题(如果坚持用FromSqlRaw)
你的原始SQL拼接存在SQL注入风险,必须改用参数化查询:
var baseQuery = @"SELECT * FROM tblAttendance WHERE 1=1 "; var parameters = new List<SqlParameter>(); if (!string.IsNullOrEmpty(userName)) { baseQuery += "AND UserName = @userName "; parameters.Add(new SqlParameter("@userName", userName)); } if (!string.IsNullOrEmpty(computerName)) { baseQuery += "AND ComputerName = @computerName "; parameters.Add(new SqlParameter("@computerName", computerName)); } if (loginDate.Ticks > 0) { baseQuery += "AND DATEPART(year, LoginDate) = @year AND DATEPART(month, LoginDate) = @month "; parameters.Add(new SqlParameter("@year", loginDate.Year)); parameters.Add(new SqlParameter("@month", loginDate.Month)); } var results = dbContext.tblAttendances.FromSqlRaw(baseQuery, parameters.ToArray()).ToList();
内容的提问来源于stack exchange,提问作者Geoff
相关产品推荐
相关产品推荐

