MvcContrib Grid Sorting on complex object

爷,独闯天下 提交于 2019-12-04 11:13:55

The issue here isn't actually related to the grid, but rather to the .OrderBy extension method provided as part of the MvcContrib sorting extensions. This extension is fairly simplistic and I only wrote it to cover simple cases where you want to sort on a direct property of the object, however in your case you're trying to order on a nested property ("priority.codeDesc") which isn't supported - you can't use dot notation with this extension.

You'd either need to switch to using a different mechanism to perform the actual sorting, or if this is a one-off situation then you could hard-code the sorting logic for this particular column (not ideal, but if it's a one off then it's simpler than writing a new sorting mechanism), eg:

if (!string.IsNullOrEmpty(sort.Column))
{
    if(sort.Column == "priority.codeDesc") 
    {
        issues = issues.OrderBy(x => x.priority.codeDesc);
    } 
    else
    {
        issues = issues.OrderBy(sort.Column, sort.Direction);
    }
}

OMG! Dots!

I was in the same boat but thanks God I found a brilliant solution posted by our fellow developer Jarrett Meyer. I found it after maybe 3 hours Googling in the past and just now when I decided to boost my pagination and sorting with MvcContrib Grid.

You can find the full post here:

Server-Side Sorting With Dynamic LINQ

His code saved me... :D The use of LINQ's Aggregate function was AWESOME! Kudozzz to him.

I had to change Jarretts' original code a little bit to fit it to my needs. Here's the code after I modified it:

public static IQueryable<T> OrderBy<T>(this IQueryable<T> collection, GridSortOptions sortOptions)
{
    if (string.IsNullOrEmpty(sortOptions.Column))
    {
        return collection;
    }

    Type collectionType = typeof(T);

    ParameterExpression parameterExpression = Expression.Parameter(collectionType, "p");

    Expression seedExpression = parameterExpression;

    Expression aggregateExpression = sortOptions.Column.Split('.').Aggregate(seedExpression, Expression.Property);

    MemberExpression memberExpression = aggregateExpression as MemberExpression;

    if (memberExpression == null)
    {
        throw new NullReferenceException(string.Format("Unable to cast Member Expression for given path: {0}.", sortOptions.Column));
    }

    LambdaExpression orderByExp = Expression.Lambda(memberExpression, parameterExpression);

    const string orderBy = "OrderBy";

    const string orderByDesc = "OrderByDescending";

    Type childPropertyType = ((PropertyInfo)(memberExpression.Member)).PropertyType;

    string methodToInvoke = sortOptions.Direction == MvcContrib.Sorting.SortDirection.Ascending ? orderBy : orderByDesc;

    var orderByCall = Expression.Call(typeof(Queryable), methodToInvoke, new[] { collectionType, childPropertyType }, collection.Expression, Expression.Quote(orderByExp));

    return collection.Provider.CreateQuery<T>(orderByCall);
}

Now you can call this extension method like this in your controller method:

var users = Database.Memberships.OrderBy(sort);

where sort is GridSortOptions that lives in MvcContrib.UI.Grid.

sort.ColumnName can contain strings like these ones now:

User.UserName
User.MyRelatedEntity.RelatedEntityProperty
User.MyRelatedEntity.RelatedEntityProperty.AndSoON 

Note that when you create your Grid columns you can specify

.SortColumnName("User.UserName")
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!