【问题标题】:Expression.Convert() not working correctly for datetime datatype in EF CoreExpression.Convert() 对于 EF Core 中的日期时间数据类型无法正常工作
【发布时间】:2019-09-18 10:14:12
【问题描述】:

在 .Net 标准 2.0 项目中,我使用 Microsoft.EntityFrameworkCore nuget 版本 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);

查询执行后失败并抛出错误消息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.0000000update_date 是 SQL Server user 表中的 datetime 列。

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

更新:如果格式是2018-03-24T00:00:01.000,它就可以工作。

【问题讨论】:

  • MSSQL Server Mgmt Studio 中的结果以2018-03-23 11:14:37.000 格式返回。
  • 您是否告诉 EF Core 列类型是 datetime?例如流利地通过 .HasColumnType("datetime")` 或 [Column] 属性?
  • 谢谢@IvanStoev。添加.HasColumnType("datetime") 后它起作用了。有没有其他/简单的方法可以做到这一点?我问这个是因为有 1000 多个表,我必须手动为所有 datetime 字段添加相同的表。
  • 请参阅下面答案中的链接。它适用于decimal,但可以调整为DateTime

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


【解决方案1】:

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

如果您需要为多列设置此项,您可以使用类似于Loop/reflect through all properties in all EF Models to set 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,您将获得更好的SQL 翻译。前者代表逻辑与(C#&amp;&amp; 运算符),而后者是通常不在逻辑表达式中使用的按位与(C#&amp; 运算符)。 Expression.OrElseExpression.Or 相同。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-08-05
    • 2016-01-02
    • 2017-07-09
    • 2018-07-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多