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

本文关键字:属性 类型 lambda 表达式 OrderBy 动态 | 更新日期: 2023-09-27 18:08:56

我试图动态创建将通过实体框架从数据库排序数据的表达式。但我遇到了一个无法克服的问题。也许让我解释一下我在做什么。我的目标是创建这样的表达式:

x => x.Property

其中"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 "的表达式不能用于返回类型" System.IComparable "

据我所知,问题是我使用"IComparable"类型,其中"MyNullableDecimalProperty"是空的,空的不用户IComparable接口。当我通过"MyLongProperty"排序或替换"IComparable"时,不会抛出异常。

我的问题是:

  1. 我应该使用什么类型来使它与任何可空属性一起工作?

  2. 是否可能使用一种类型,它将适用于所有属性,无论它们是可空的还是不可空的

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

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

没有理由使用IComparable。实际上,许多类似的类型都没有实现IComparable。只要使用你要传递的运行时类型:

var finalExpression = Expression.Call(
    typeof (Queryable),
    "OrderBy",
    new[] { list.ElementType, propertyToOrder.Type },
    list.Expression,
    Expression.Lambda(propertyToOrder, new [] { argument }));

您不需要指定IComparable部分,您也可以使用Queryable。OrderBy/orderby降序方法来帮助你:

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)

试一试,看看效果如何,我很确定这对原生类型和可空类型都有效。