c# - 如何修复 SqlError :failed when converting date and/or time from character string. EF 二进制表达式?

标签 c# sql linq sqlclient

我正在尝试使用表达式动态创建与 Entity Framework Core 2.2 一起使用的比较操作。除了约会之外,其他一切都可以正常工作。

这是查询

new System.Linq.Expressions.Expression.MethodCallExpressionProxy(((Remotion.Linq.QueryableBase<ORMModel.Sale>)tq).Expression).DebugView

.Call System.Linq.Queryable.Where(
.Constant<Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable`1[ORMModel.Sale]>(Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable`1[ORMModel.Sale]),
'(.Lambda #Lambda1<System.Func`2[ORMModel.Sale,System.Boolean]>))

.Lambda #Lambda1<System.Func`2[ORMModel.Sale,System.Boolean]>(ORMModel.Sale $Sale) {
$Sale.CreateDT > (System.DateTime).Constant<System.DateTime>(12/25/2018 5:00:00 AM)
}

这是我得到的错误

System.Data.SqlClient.SqlError
Conversion failed when converting date and/or time from character string.

我已直接在 SQL Server Management Studio 中使用该日期值并执行它。

任何对无知者的帮助或线索表示赞赏。太多的谷歌搜索却一无所获。每个示例都是 SQL 字符串而不是动态表达式。

public static Expression GetBinaryExpression<TSource>(string propertyName, int comparer, dynamic valueIn)
{
    PropertyInfo pi = GetPropertyInfo<TSource>(propertyName);
    Type pt = pi.PropertyType;

    var parameter = Expression.Parameter(typeof(TSource), typeof(TSource).Name);
    var property = Expression.Property(parameter, propertyName);

    dynamic valueTyped;

    if (IsNullableType(pt))
    {
        valueTyped = Convert.ChangeType(valueIn, Nullable.GetUnderlyingType(pt));
    }
    else
    {
        valueTyped = Convert.ChangeType(valueIn, pt);
    }

    var constant = Expression.Constant(valueTyped);

    var val = Expression.Convert(constant, pt);

    Expression exp = null;

    switch (comparer)
    {
        case 1:
            exp = Expression.Equal(property, val);
            break;
        case 2:
            exp = Expression.NotEqual(property, val);
            break;
        case 3:
            exp = Expression.GreaterThan(property, val);
            break;
        case 4:
            exp = Expression.GreaterThanOrEqual(property, val);
            break;
        case 5:
            exp = Expression.LessThan(property, val);
            break;
        case 6:
            exp = Expression.LessThanOrEqual(property, val);
            break;
    }

    if (exp.CanReduce) exp = exp.Reduce();

    return Expression.Lambda<Func<TSource, Boolean>>(exp, parameter);
}

private static bool IsNullableType(Type type)
{
    return type.IsGenericType && 
    type.GetGenericTypeDefinition().Equals(typeof(Nullable<>));
}

我希望返回一个漂亮的结果集,而不是一个令人恼火的错误。

最佳答案

SQL Server 数据类型映射是该问题的解决方案。根据我的研究,SqlCommand 对象依赖于数据类型映射来从 CLR 转换为 SQL 数据类型。

当涉及到 DateTime 时,使用常量表达式没有帮助,因为它被序列化为如下字符串格式:

'2020-05-03T14:32:05.000435Z'

例如,生成的 sql 如下所示:

SELECT [s].[Routine], [s].[CreatedOn] FROM Routines as s
WHERE [s].[CreatedOn] >= '2020-05-03T14:32:05.000435Z'

如果日期字符串格式是这样的:''2020-05-03T14:32:05'那么sql服务器会很高兴,但是唉,表达式对于数据类型是如此严格,你不能将此字符串格式传递给 DateTime 属性。

废话够多了,让我们看一下代码:

...

Expression<Func<TProperty>> exprValueVar = () => valueTyped;

exp = Expression.Equal(property, exprDateVar.Body);

...

lambda 表达式:

Expression<Func<TProperty>> exprValueVar = () => valueTyped;

成功并允许 DbSet 生成 sql 参数化命令。

一旦使用 DbSet 执行,生成的 IQueryable 将是带有参数的命令。这可以从生成的 sql 中验证,数据类型映射现在可以将 CLR 数据类型转换为 SQL 数据类型,而不会抛出可怕的“从字符串转换日期和/或时间时转换失败”。

关于c# - 如何修复 SqlError :failed when converting date and/or time from character string. EF 二进制表达式?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55313535/

相关文章:

java - 如何将日期时间嵌入到 SQL 字符串中

php - 我如何获得特定用户的最后 7 个投注单 (BetSlipID)

c# - Linq 查询组合两个或三个表达式

c# - 从客户端对象 API 访问 TFS 团队查询

c# - 使用 ExpressionVisitor 从表达式中删除条件

c# - 找不到 WS-Security header

c# - 创建不具有实体类型属性的动态 LINQ 语句

mysql - mysql问题

c# - 如何在 .ForEach() 方法中使用 continue 语句

c# - 通用方法无法在 IEnumerable<T> 上利用协方差