我正在尝试使用表达式动态创建用于实体框架核心 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
转换失败时,从字符串转换日期和/或时间。
我直接在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 数据类型,而不会抛出可怕的"从字符串转换日期和/或时间时转换失败"。