Access nested properties with dynamic lambda using

2019-04-21 09:31发布

Let's assume that I have two classes:

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

These classes are more or less given, they are mapped via nHibernate to be honest :)

In a grid (datatables.net as base) I would like to have a type-independent sorting.

Therefore I created a lambda expression:

  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);

If I pass Person as Type T and replace the "Property to sort" with "name" it works fine (creates a correct lambda). If the Property to sort is "address.street" it won't work, throw me the following error:

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

I see only one solution so far, but not clear enough... I would try to split the string which contains the Property-Name (split by .)

Can anyone give a better solution? I need to add the sortExpression to an IQueryable object query.OrderBy(sortExpression).

Not sure if my title is clear, please go ahead and correct it.

Thanks in advance.

4条回答
ら.Afraid
2楼-- · 2019-04-21 09:47

What is not clear?

You have to split it and then use:

Expression.Property(Expression.Property(param, "address"), "street")
查看更多
我命由我不由天
3楼-- · 2019-04-21 09:56

Here's a more generic version of LukLed's answer:

    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);
    }

You can use it like this:

var paramExpression = Expression.Parameter(this.type, "val");
var firstProp = NestedExpressionProperty(paramExpression,"address.street");
查看更多
狗以群分
4楼-- · 2019-04-21 10:08

Try this one

    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);
    }
查看更多
等我变得足够好
5楼-- · 2019-04-21 10:10

It seems to me you're trying to rewrite Microsoft DynamicQuery. Why not just use that instead?

Here's an example:

IQueryable<Foo> myQuery = GetHibernateQuery();
myQuery = myQuery.OrderBy("address.street");
查看更多
登录 后发表回答