动态lambda表达式(OrderBy)和可空属性类型

时间:2015-08-19 14:34:09

标签: c# linq entity-framework lambda expression-trees

我试图动态创建表达式,通过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;。

所以我的问题:

  1. 我应该使用哪种类型来使其适用于任何可以为空的属性?

  2. 是否可以使用一种类型,它可以与所有属性一起使用,无论它们是可空的还是不可为空的。

  3. 注意:我知道我可以使用ex。动态Linq库,但我对此解决方案不感兴趣 - 我想学习如何在不使用第三方库的情况下克服它。

2 个答案:

答案 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)

放手一搏,看看你是如何进行的,我非常确定这适用于原生类型和可空类型。