使用Linq.Expression访问具有动态lambda的嵌套属性

时间:2009-11-04 14:21:19

标签: asp.net-mvc linq lambda

我们假设我有两个类:

class person
{
    int ID
    string name
    Address address
}
class address
{
    int ID
    string street
    string country
}

这些类或多或少是给定的,它们通过nHibernate映射为诚实:)

在网格中(datatables.net作为基础)我希望有一个与类型无关的排序。

因此我创建了一个lambda表达式:

  var param = Expression.Parameter(typeof(T), typeof(T).Name);
  var sortExpression = Expression.Lambda<Func<T, object>>
                              (Expression.Convert(Expression.Property(param, "Property to sort"), typeof(object)), param);

如果我将Person作为类型T传递并将“Property to sort”替换为“name”,则它可以正常工作(创建一个正确的lambda)。如果要排序的属性是“address.street”它将无法正常工作,请抛出以下错误:

Property 'address.street' is not defined for type 'person'

到目前为止我只看到一个解决方案,但不够清楚......我会尝试拆分包含Property-Name的字符串(拆分。)

任何人都可以提供更好的解决方案吗?我需要将sortExpression添加到IQueryable对象query.OrderBy(sortExpression)

不确定我的标题是否清晰,请继续纠正。

提前致谢。

4 个答案:

答案 0 :(得分:12)

什么不清楚?

你必须拆分然后使用:

Expression.Property(Expression.Property(param, "address"), "street")

答案 1 :(得分:4)

这是LukLed答案的更通用版本:

    protected MemberExpression NestedExpressionProperty(Expression expression, string propertyName)
    {
        string[] parts = propertyName.Split('.');
        int partsL = parts.Length;

        return (partsL > 1) 
            ? 
            Expression.Property( 
                NestedExpressionProperty(
                    expression, 
                    parts.Take(partsL - 1)
                        .Aggregate((a, i) => a + "." + i)
                ), 
                parts[partsL - 1]) 
            :
            Expression.Property(expression, propertyName);
    }

你可以像这样使用它:

var paramExpression = Expression.Parameter(this.type, "val");
var firstProp = NestedExpressionProperty(paramExpression,"address.street");

答案 2 :(得分:2)

在我看来,你正在尝试重写Microsoft DynamicQuery。为什么不直接使用呢?

以下是一个例子:

IQueryable<Foo> myQuery = GetHibernateQuery();
myQuery = myQuery.OrderBy("address.street");

答案 3 :(得分:0)

试试这个

    public static IQueryable<T> SortIQueryable<T>(IQueryable<T> data, string fieldName, string sortOrder)
    {
        if (string.IsNullOrWhiteSpace(fieldName)) return data;
        if (string.IsNullOrWhiteSpace(sortOrder)) return data;

        var param = Expression.Parameter(typeof(T), "i");

        MemberExpression property = null;
        string[] fieldNames = fieldName.Split('.');
        foreach (string filed in fieldNames)
        {
            if (property == null)
            {
                property = Expression.Property(param, filed);
            }
            else
            {
                property = Expression.Property(property, filed);
            }
        }

        Expression conversion = Expression.Convert(property, typeof(object));//Expression.Property(param, fieldName)
        var mySortExpression = Expression.Lambda<Func<T, object>>(conversion, param);

        return (sortOrder == "desc") ? data.OrderByDescending(mySortExpression)
            : data.OrderBy(mySortExpression);
    }