动态 lambda 表达式 (OrderBy) 和可为空的 属性 类型
Dynamic lambda expression (OrderBy) and nullable property type
我正在尝试动态创建表达式,通过 Entity Framework 对数据库中的数据进行排序。但是我遇到了一个问题,无法克服。也许让我解释一下我想做什么。我的目标是创建这样的表达式:
x => x.Property
其中 "Property" 是我想动态指定的 属性 的名称。
现在,让我们转到 class,它代表数据库中的 table(我将其简化以使事情更清楚):
public class MyModelClass
{
public long MyLongProperty { get; set; }
public decimal? MyNullableDecimalProperty { get; set; } // IMPORTANT: it's nullable
}
这是我的代码,我在其中尝试创建前面描述的表达式:
// Db is EntityFramework context
IQueryable<MyModelClass> list = Db.MyModels.Select(x => x);
// x =>
var argument = Expression.Parameter(list.ElementType, "x");
// x.MyNullableDecimalProperty
var propertyToOrder = Expression.Property(argument, "MyNullableDecimalProperty");
// x => x.MyNullableDecimalProperty
var finalExpression = Expression.Call(
typeof (Queryable),
"OrderBy",
new[] { list.ElementType, typeof(IComparable) },
list.Expression,
Expression.Lambda<Func<MyModelClass, IComparable>>(propertyToOrder, argument));
list = list.Provider.CreateQuery<MyModelClass>(finalExpression);
问题出现在第 4 个语句 (var finalExpression = Expression.Call(...))。我得到一个例外:
Expression of type „System.Nullable`1[System.Decimal]” cannot be used for return type „System.IComparable”.
据我所知,问题出在我使用 "IComparable" 类型,其中 "MyNullableDecimalProperty" 是 Nullable 并且 Nullable 不使用 IComparable 接口。当我按 "MyLongProperty" 订购或替换 "IComparable".
时,不会抛出异常
所以我的问题:
我应该使用什么类型来使其与任何可为 null 的属性一起工作?
是否可以使用一种类型并且它适用于所有属性,无论它们是可为空还是不可为空。
注意:我知道我可以用于ex。动态 Linq 库,但我对此解决方案不感兴趣 - 我想学习如何在不使用第 3 方库的情况下克服它。
您不需要指定 IComparable 部分,您也可以使用 Queryable.OrderBy / OrderByDescending 方法在这里帮助您:
IQueryable<TSource> source = .....
var sourceType = typeof(TSource);
var parameter = Expression.Parameter(sourceType, "item");
var propertyInfo = GetProperty(sourceType, propertyName);
var orderByProperty = Expression.Property(parameter, propertyInfo);
orderBy = Expression.Lambda(orderByProperty, new[] { parameter });
return Queryable.OrderBy(source, (dynamic)orderBy)
试一试,看看进展如何,我很确定这对本机类型和可空类型都有效。
没有理由使用 IComparable
。事实上,许多可比较的类型并没有实现 IComparable
。只需使用您传递的任何内容的运行时类型:
var finalExpression = Expression.Call(
typeof (Queryable),
"OrderBy",
new[] { list.ElementType, propertyToOrder.Type },
list.Expression,
Expression.Lambda(propertyToOrder, new [] { argument }));
我正在尝试动态创建表达式,通过 Entity Framework 对数据库中的数据进行排序。但是我遇到了一个问题,无法克服。也许让我解释一下我想做什么。我的目标是创建这样的表达式:
x => x.Property
其中 "Property" 是我想动态指定的 属性 的名称。
现在,让我们转到 class,它代表数据库中的 table(我将其简化以使事情更清楚):
public class MyModelClass
{
public long MyLongProperty { get; set; }
public decimal? MyNullableDecimalProperty { get; set; } // IMPORTANT: it's nullable
}
这是我的代码,我在其中尝试创建前面描述的表达式:
// Db is EntityFramework context
IQueryable<MyModelClass> list = Db.MyModels.Select(x => x);
// x =>
var argument = Expression.Parameter(list.ElementType, "x");
// x.MyNullableDecimalProperty
var propertyToOrder = Expression.Property(argument, "MyNullableDecimalProperty");
// x => x.MyNullableDecimalProperty
var finalExpression = Expression.Call(
typeof (Queryable),
"OrderBy",
new[] { list.ElementType, typeof(IComparable) },
list.Expression,
Expression.Lambda<Func<MyModelClass, IComparable>>(propertyToOrder, argument));
list = list.Provider.CreateQuery<MyModelClass>(finalExpression);
问题出现在第 4 个语句 (var finalExpression = Expression.Call(...))。我得到一个例外:
Expression of type „System.Nullable`1[System.Decimal]” cannot be used for return type „System.IComparable”.
据我所知,问题出在我使用 "IComparable" 类型,其中 "MyNullableDecimalProperty" 是 Nullable 并且 Nullable 不使用 IComparable 接口。当我按 "MyLongProperty" 订购或替换 "IComparable".
时,不会抛出异常所以我的问题:
我应该使用什么类型来使其与任何可为 null 的属性一起工作?
是否可以使用一种类型并且它适用于所有属性,无论它们是可为空还是不可为空。
注意:我知道我可以用于ex。动态 Linq 库,但我对此解决方案不感兴趣 - 我想学习如何在不使用第 3 方库的情况下克服它。
您不需要指定 IComparable 部分,您也可以使用 Queryable.OrderBy / OrderByDescending 方法在这里帮助您:
IQueryable<TSource> source = .....
var sourceType = typeof(TSource);
var parameter = Expression.Parameter(sourceType, "item");
var propertyInfo = GetProperty(sourceType, propertyName);
var orderByProperty = Expression.Property(parameter, propertyInfo);
orderBy = Expression.Lambda(orderByProperty, new[] { parameter });
return Queryable.OrderBy(source, (dynamic)orderBy)
试一试,看看进展如何,我很确定这对本机类型和可空类型都有效。
没有理由使用 IComparable
。事实上,许多可比较的类型并没有实现 IComparable
。只需使用您传递的任何内容的运行时类型:
var finalExpression = Expression.Call(
typeof (Queryable),
"OrderBy",
new[] { list.ElementType, propertyToOrder.Type },
list.Expression,
Expression.Lambda(propertyToOrder, new [] { argument }));