解析OData日期过滤字符串时的SQL日期转换错误排查
解决Radzen DateTime过滤SQL带时间导致的转换错误
问题背景
用Radzen做视图数据集的过滤器,大部分场景没问题,但DateTime过滤时弹出错误:Conversion failed when converting date and/or time from character string.,查了下生成的SQL,发现是带了多余的时间戳:
SELECT [a].[SellBy] , [a].[ProductName] FROM [dbo].[Products] AS [a] WHERE [a].[SellBy] = '2023-02-05T00:00:00.0000000'
当前我处理OData过滤转换的代码是这样的:
if (IsNullableType(left.Type) && !IsNullableType(right.Type)) { if(right is ConstantExpression offset) { if(offset.Value is DateTimeOffset dateTimeOffset) { DateTime? dateTime = dateTimeOffset.DateTime; right = ConstantExpression.Constant(dateTime, typeof(DateTime?)); } } }
把这个表达式传给EF的Where子句后,还是生成带时间的SQL。我的OData查询是:
SellBy eq 2023-09-06T00:00:00.000Z
需要实现的是:解析这个OData过滤字符串,支持=、<>、<、<=、>、>=`这些日期比较,而且生成的SQL不能带时间部分。
可行解决方案
方案一:修改表达式转换逻辑,只保留日期部分
原来的代码只是把DateTimeOffset转成了DateTime?,但还是带时间戳。改成直接提取日期部分,再生成常量表达式:
if (IsNullableType(left.Type) && !IsNullableType(right.Type)) { if(right is ConstantExpression offset) { if(offset.Value is DateTimeOffset dateTimeOffset) { // 只取日期部分,转成DateTime? DateTime? dateOnly = dateTimeOffset.Date; right = ConstantExpression.Constant(dateOnly, typeof(DateTime?)); // 如果数据库里SellBy是Date类型,直接用DateOnly更精准(EF Core 6+支持) // DateOnly? dateOnly = DateOnly.FromDateTime(dateTimeOffset.Date); // right = ConstantExpression.Constant(dateOnly, typeof(DateOnly?)); } } }
这样EF生成的SQL里,常量就只会是'2023-02-05'这种纯日期格式。
方案二:用EF函数截断数据库字段的时间(兼容旧EF版本)
如果没法直接修改常量类型,可以在构建过滤表达式时,对数据库的DateTime字段做截断处理,用EF.Functions.TruncateTime把时间部分去掉:
// 假设left是代表SellBy字段的MemberExpression var truncatedLeft = Expression.Call( typeof(EF), nameof(EF.Functions.TruncateTime), Type.EmptyTypes, left ); // 用截断后的字段表达式和常量做比较 var comparison = Expression.MakeBinary(expressionType, truncatedLeft, right);
生成的SQL会变成这样:
WHERE CAST([a].[SellBy] AS DATE) = '2023-02-05'
方案三:解析OData过滤字符串时直接提取日期
从OData的过滤字符串里直接把日期部分抠出来,不用管后面的时间戳:
var oDataFilter = "SellBy eq 2023-09-06T00:00:00.000Z"; // 用正则匹配日期部分 var regex = new Regex(@"(\d{4}-\d{2}-\d{2})T"); var match = regex.Match(oDataFilter); if (match.Success) { var dateStr = match.Groups[1].Value; DateTime date = DateTime.Parse(dateStr); // 用这个纯日期的date来构建比较表达式就行 }
注意事项
- 如果数据库里的
SellBy是Date类型,优先用DateOnly,匹配更精准,不会有时间部分的隐患 - 别忘测试所有比较运算符,确保每个都能生成正确的无时间SQL
- 要是用的EF Core 6以下版本,
DateOnly不支持,就用DateTime.Date的方式处理
内容的提问来源于stack exchange,提问作者adc90
相关产品推荐
相关产品推荐

