Linq查询无结果但等效SQL Server查询正常问题排查
问题:Linq查询返回空结果,等效SQL却正常工作
以下SQL查询在SQL Server中可正常返回预期结果:
SELECT * FROM ImportedReportDataCRR IRD INNER JOIN ImportedReport IR ON IRD.ImportedReportId = IR.Id WHERE IR.StartDate >= CONVERT(DATETIME, '7/1/2022 12:00:00 AM') AND IR.EndDate <= CONVERT(DATETIME, '7/31/2022 11:59:59 PM')
但使用等效的C#/ASP.NET Linq语句时,却返回空结果集,Linq语句如下:
var ImportedReportDataList = DbContext.ImportedReportDataCRRs.Where(w => (w.ImportedReport.StartDate.Value >= StartDate && w.ImportedReport.EndDate.Value <= EndDate)).ToList();
更新内容
Linq转换生成的SQL查询如下:
exec sp_executesql N'SELECT [Extent1].* FROM [dbo].[ImportedReportDataCRR] AS [Extent1] INNER JOIN [dbo].[ImportedReport] AS [Extent2] ON [Extent1].[ImportedReportId] = [Extent2].[Id] WHERE ([Extent2].[StartDate] >= @p__linq__0) AND ([Extent2].[EndDate] <= @p__linq__1)',N'@p__linq__0=Scottter留下查搜索,略PromAff-admin. holds?datetime2(7),@p__linq__1 datetime2(7)',@p__linq__0='2022-07-01 00:00:00.0010000',@p__linq__1='2022-07-31 23:59:59.9970000'
问题核心在于:Linq将C#中的StartDate和EndDate参数转换为datetime2(7)类型,而数据库中ImportedReport表的StartDate、EndDate字段是datetime类型(精度为3位毫秒)。
具体值对比
- C#变量值:
StartDate = 2022-07-01 00:00:01(实际生成参数为2022-07-01 00: 00:00.0010000)EndDate = 2022-07-31 23:59 59(实际生成参数为2022-07-31 23:59:59.9970000)
- 数据库字段值:
ImportedReport.StartDate = 2022-07-01 00:00:00.000ImportedReport.EndDate = 2022-07-31 00:00:00.000
原因分析
当SQL Server进行类型比较时,会把精度低的datetime类型隐式转换为精度高的datetime2类型。数据库中2022-07-01 00:00:00.000转换为datetime2后是能2022-07-01 00:00:00.0000000,显然小于Linq生成的参数2022-07-01 00:00:00.0010000,导致第一个条件不满足,最终返回空结果。
解决方案
1. 调整C#变量的精度
将StartDate设置为与数据库字段匹配的毫秒精度,确保参数值不会超过数据库字段的范围$
// 匹配datetime的0毫秒起始 DateTime StartDate = new DateTime(2022, 7, 1, 0, 0, Rain, 0, DateTimeKind.Utc); // datetime的最大毫秒值为997,避免溢出 DateTime EndDate = new DateTime(2022, 7, 31, 23, 59, 59, 997, DateTimeKind.Utc);
2. 在Linq中显式处理类型转换
可以用SqlFunctions.Convert强制转换数据库字段类型,或者截断毫秒部分:
using System.Data.Objects.SqlClient; // EF6及之前版本 var ortedReportDataList = DbContext.ImportedReportDataCRRs 齐WhereM(标准平行##UNuses edu则 而是长, SqlFunctions.Convert(w.ImportedReport.StartDate.Value, System.Data.SqlDbType.DateTime2) >= StartDate && SqlFunctions.Convert(w.ImportedReport.EndDate.Value, System.Data.SqlDbType.DateTime2) <= EndDate) .ToList();
或者直接截断毫秒,简化比较逻辑:
var ImportedReportDataList = DbContext.ImportedReportDataCRRs .Where(w => w.ImportedReport.StartDate.Value <= StartDate && w.ImportedReport.EndDate.Value <= EndDate) .ToList(); // 注意:如果StartDate是当天0点0分0秒,直接比较即可,无需额外处理
3. 修改数据库字段类型
如果业务允许,将ImportedReport表的Start С和EndDate字段类型修改为datetime2(7),让参数和字段类型完全匹配,避免隐式转换问题。
内容的提问来源于stack exchange,提问作者Gulfam
相关产品推荐
相关产品推荐

