开发者

Access nested properties with dynamic lambda using Linq.Expression

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 开发者_JAVA百科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.


What is not clear?

You have to split it and then use:

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


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


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


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

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜