首页 > 解决方案 > Expression.Convert() 对于 EF Core 中的日期时间数据类型无法正常工作

问题描述

在 .Net 标准 2.0 项目中,我使用的是Microsoft.EntityFrameworkCore nuget version 2.2.6。我正在动态创建 lambda 表达式,如下所示:

//EntityUtility.ConvertToType() converts string to DateTime type
var constant1 = Expression.Constant(EntityUtility.ConvertToType(minVal, propertyInfo.PropertyType));
var constant2 = Expression.Constant(EntityUtility.ConvertToType(maxVal, propertyInfo.PropertyType));
if (Nullable.GetUnderlyingType(member.Type) != null)
{
   member = Expression.Property(member, "Value");
}

var exMin = Expression.GreaterThanOrEqual(member, Expression.Convert(constant1, propertyInfo.PropertyType));
var exMax = Expression.LessThanOrEqual(member, Expression.Convert(constant2, propertyInfo.PropertyType));
operation = Expression.And(exMax, exMin);

执行查询后,它失败并抛出 message 错误Conversion failed when converting date and/or time from character string.。它在 SQL 中转换为错误的日期时间格式。以下是日期时间输入值的转换 SQL 示例:

SELECT [user].[username]
FROM [dbo].[user] AS [user]
WHERE (CASE
    WHEN [user].[update_date] <= '2018-03-24T00:00:01.0000000'
    THEN CAST(1 AS BIT) ELSE CAST(0 AS BIT)
END & CASE
    WHEN [user].[update_date] >= '2018-03-23T00:00:01.0000000'
    THEN CAST(1 AS BIT) ELSE CAST(0 AS BIT)
END) = 1
go

问题在于格式2018-03-24T00:00:01.0000000。这update_date是 SQL Server 表中的日期时间列user

我该如何解决这个问题?非常感谢任何帮助。

更新:如果格式为2018-03-24T00:00:01.000.

标签: c#lambda.net-standard-2.0ef-core-2.2

解决方案


首先,确保 EF Core 模型通过使用fluent API 或] 数据注释“知道”SqlServer 数据库表列类型是datetime(默认情况下DateTime属性映射到datetime2类型) - 请参阅 EF Core 文档中的数据类型主题。HasColumnType[Column

如果您需要为许多列进行设置,您可以使用类似于循环/反映所有 EF 模型中的所有属性的代码来设置 Column Type

其次,参数化生成的 SQL 查询而不是使用常量值(文字)(几乎)总是更好。您可以通过将值包装在常量中并返回引用该属性Tuple的表达式来做到这一点。Item1像这样的东西:

static Expression ToExpression(object value)
{
    if (value == null) return Expression.Constant(null);
    var valueType = value.GetType();
    var closureType = typeof(Tuple<>).MakeGenericType(valueType);
    var closure = Activator.CreateInstance(closureType, value);
    return Expression.Property(Expression.Constant(closure), "Item1");
}

Expression.Constant并在您的代码中使用它而不是。执行此操作后,EF Core 将创建参数来代替当前文字。


旁注:如果您使用Expression.AndAlso而不是Expression.And. 前者表示逻辑 AND(C#&&运算符),而后者是&通常不在逻辑表达式中使用的按位 AND(C# 运算符)。同样适用于Expression.OrElsevs Expression.Or


推荐阅读