我试图动态创建表达式,通过Entity Framework对数据库中的数据进行排序。但我遇到了一个问题,无法克服它。也许让我解释一下我想做什么。我的目标是创建这样的表达式:
x => x.Property
在哪里"财产"是我想动态指定的属性名称。
现在,让我们转到类,它代表数据库中的表(我简化了它以使事情更清晰):
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(...))。我得到一个例外:
“System.Nullable .1 [System.Decimal]”类型的表达式不能用于返回类型“System.IComparable”。
据我所知,问题在于我使用&#34; IComparable&#34;输入&#34; MyNullableDecimalProperty&#34;是Nullable和Nullable不是用户IComparable接口。当我通过&#34; MyLongProperty&#34;订购时,不会抛出例外情况。或当我更换&#34; IComparable&#34;。
所以我的问题:
我应该使用哪种类型来使其适用于任何可以为空的属性?
是否可以使用一种类型,它可以与所有属性一起使用,无论它们是可空的还是不可为空的。
注意:我知道我可以使用ex。动态Linq库,但我对此解决方案不感兴趣 - 我想学习如何在不使用第三方库的情况下克服它。
答案 0 :(得分:2)
没有理由使用IComparable
。实际上,许多可比较的类型没有实现IComparable
。只需使用您传递的任何内容的运行时类型:
var finalExpression = Expression.Call(
typeof (Queryable),
"OrderBy",
new[] { list.ElementType, propertyToOrder.Type },
list.Expression,
Expression.Lambda(propertyToOrder, new [] { argument }));
答案 1 :(得分:0)
您不需要指定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)
放手一搏,看看你是如何进行的,我非常确定这适用于原生类型和可空类型。