You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

解析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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 21:05:14