MvcContrib网格对复杂对象进行排序

时间:2011-07-05 10:24:52

标签: linq sorting grid sql-order-by mvccontrib

我正在尝试使用MvcContrib网格控件。但我似乎无法对包含其他对象的复杂对象进行排序。

我在这个问题中设置了类似于OP的控制器/类/视图。 Sorting with MVCContrib

我曾尝试将SortColumnName用于我的childobject.property,但它给出了一个错误,说我的主对象没有此属性。这是我的代码段

// POCO class

class Issue {
   public int ID {get; get; }
   .....
   public int priorityId {get; set;}
   public virtual Priority priority {get; set;}
}

//控制器代码

    public ViewResult Index(int? pageNo, GridSortOptions sort)
    {
        var issues = db.issues.Include(i => i.priority);
        ViewBag.sort = sort; 

        if (!string.IsNullOrEmpty(sort.Column))
        {
            issues = issues.OrderBy(sort.Column, sort.Direction);
        }
        return View(issues.ToList().AsPagination(pageNo ?? 1, 10));
    }

//查看网格的代码

@Html.Grid(Model).Sort(ViewBag.sort as GridSortOptions).Columns(column => {
    column.For(issue => Html.ActionLink(" ", "Edit", new { id = issue.ID, areas = "Issues", controller = "Main"}, new { @id="editBtn"})).Named("Edit");
    column.For(issue => Html.ActionLink(issue.ID.ToString(), "Edit", new {id = issue.ID, areas = "Issues", controller = "Main"})).Named("ID").Sortable(true);
     column.For(issue => issue.priority.codeDesc).Named("Priority").SortColumnName("priority.codeDesc").Sortable(true);
}).Empty("No data found")

当我尝试对优先级字符串进行排序时,它会给出一个错误,指出'priority.codeDesc不是Issue的属性'。

TIA

2 个答案:

答案 0 :(得分:3)

此处的问题实际上与网格无关,而是与作为MvcContrib排序扩展的一部分提供的.OrderBy扩展方法有关。这个扩展是相当简单的,我只编写它来涵盖你想要对对象的直接属性进行排序的简单情况,但是在你的情况下你试图在嵌套属性(“priority.codeDesc”)上进行排序不支持 - 你不能在这个扩展名上使用点符号。

您需要切换到使用不同的机制来执行实际排序,或者如果这是一次性情况,那么您可以对此特定列的排序逻辑进行硬编码(不理想,但如果是然后它比编写新的排序机制更简单,例如:

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

答案 1 :(得分:1)

OMG!点!

我在同一条船上,但感谢上帝,我找到了由我们的同事Jarrett Meyer发布的精彩解决方案。我发现它可能是过去3个小时的谷歌搜索,刚才我决定用MvcContrib网格来提升我的分页和排序。

您可以在此处找到完整的帖子:

Server-Side Sorting With Dynamic LINQ

他的代码救了我......:D使用LINQ's Aggregate功能真棒! Kudozzz对他说。

我必须稍微更改Jarretts的原始代码以符合我的需要。这是修改后的代码:

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

现在您可以在控制器方法中调用此扩展方法:

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

其中sort是位于MvcContrib.UI.Grid的GridSortOptions。

sort.ColumnName现在可以包含这些字符串:

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

请注意,在创建Grid列时,您可以指定

.SortColumnName("User.UserName")