Expression.Convert() 对于 EF Core 中的日期时间数据类型无法正常工作
Expression.Convert() not working correctly for datetime datatype in EF Core
在 .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.0000000
格式中。 update_date
是 SQL 服务器 user
table 中的 日期时间 列。
我该如何解决这个问题?非常感谢任何帮助。
更新:如果格式是2018-03-24T00:00:01.000
,它是有效的。
首先,确保 EF Core 模型 "knows" SqlServer 数据库 table 列类型为 datetime
(默认情况下 DateTime
属性映射到 datetime2
类型)通过使用 HasColumnType
流畅 API 或 [Column
] 数据注释 - 请参阅 EF Core 文档中的 Data Types 主题。
如果您需要为很多列设置此项,您可以使用类似于的代码。
其次,(几乎)总是更好地参数化生成的 SQL 查询而不是使用常量值(文字)。您可以通过将值包装在常量 Tuple
和 return 引用 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# &&
运算符),而后者是按位与(C# &
运算符),您通常不会在逻辑表达式中使用它。 Expression.OrElse
与 Expression.Or
.
相同
在 .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.0000000
格式中。 update_date
是 SQL 服务器 user
table 中的 日期时间 列。
我该如何解决这个问题?非常感谢任何帮助。
更新:如果格式是2018-03-24T00:00:01.000
,它是有效的。
首先,确保 EF Core 模型 "knows" SqlServer 数据库 table 列类型为 datetime
(默认情况下 DateTime
属性映射到 datetime2
类型)通过使用 HasColumnType
流畅 API 或 [Column
] 数据注释 - 请参阅 EF Core 文档中的 Data Types 主题。
如果您需要为很多列设置此项,您可以使用类似于
其次,(几乎)总是更好地参数化生成的 SQL 查询而不是使用常量值(文字)。您可以通过将值包装在常量 Tuple
和 return 引用 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# &&
运算符),而后者是按位与(C# &
运算符),您通常不会在逻辑表达式中使用它。 Expression.OrElse
与 Expression.Or
.