在 asp.net MVC 中对表进行排序

Posted

技术标签:

【中文标题】在 asp.net MVC 中对表进行排序【英文标题】:Sorting a table in asp.net MVC 【发布时间】:2011-01-03 04:20:14 【问题描述】:

我想知道人们是如何在 asp.net mvc 中对表格进行排序的? 我听说过适用于非分页表的 javascript 解决方案,例如 jquery 的表格排序器,但我需要一个适用于分页表的解决方案。

我正在做的项目目前使用以下解决方案,但我发现它非常混乱。

控制器

public ActionResult Sort(string parameter)
  

 IEnumerable<IProduct> list;

 if (Session["Model"] != null)
  list = (IEnumerable<IProduct>)Session["Model"]).ToList<IProduct>();
 else
  list = _service.GetAll();

 if (Session["parameter"] == null && Session["sortDirection"] == null)
 
  //set the parameter and set the sort to desc
  Session["parameter"] = parameter;
  Session["sortDirection"] = "DESC";
 
 else if (Session["parameter"] != null) //already set so not the first time
 
  //same parameter sent
  if (Session["parameter"].ToString().Equals(parameter))
  
   //check sort direction and reverse
   if (Session["sortDirection"].ToString().Equals("DESC"))
    Session["sortDirection"] = "ASC";
   else
    Session["sortDirection"] = "DESC";
  
  else //different parameter sent
  
   Session["sortDirection"] = "DESC";
   Session["parameter"] = parameter;
  
 

 if (Session["sortDirection"].CompareTo("ASC") == 0)
  list = Models.ContollerHelpers.SortingHelper.OrderBy(list.AsQueryable(), column);
 else
  list = Models.ContollerHelpers.SortingHelper.OrderByDescending(list.AsQueryable(), column);

 return View("Results", list.ToList);

助手

public class Helper()

 private static IOrderedQueryable<T> OrderingHelper<T>(IQueryable<T> source, string propertyName, bool descending, bool anotherLevel)
 
  ParameterExpression param = Expression.Parameter(typeof(T), string.Empty); // I don't care about some naming
  MemberExpression property = Expression.PropertyOrField(param, propertyName);
  LambdaExpression sort = Expression.Lambda(property, param);

  MethodCallExpression call = Expression.Call(
   typeof(Queryable),
   (!anotherLevel ? "OrderBy" : "ThenBy") + (descending ? "Descending" : string.Empty),
   new[]  typeof(T), property.Type ,
   source.Expression,
   Expression.Quote(sort));

  return (IOrderedQueryable<T>)source.Provider.CreateQuery<T>(call);
 

 public static IOrderedQueryable<T> OrderBy<T>(this IQueryable<T> source, string propertyName)
 
  return OrderingHelper(source, propertyName, false, false);
 

 public static IOrderedQueryable<T> OrderByDescending<T>(this IQueryable<T> source, string propertyName)
 
  return OrderingHelper(source, propertyName, true, false);
 

 public static IOrderedQueryable<T> ThenBy<T>(this IOrderedQueryable<T> source, string propertyName)
 
  return OrderingHelper(source, propertyName, false, true);
 

 public static IOrderedQueryable<T> ThenByDescending<T>(this IOrderedQueryable<T> source, string propertyName)
 
  return OrderingHelper(source, propertyName, true, true);
 

列表视图

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<IEnumerable<Models.Interface.IProduct>>" %>
<% Session["model"] = Model; %>
 <table>
    <tr>
   <th>
    Edit Details
   </th>
   <th>
    <%=html.ActionLink("Id","Sort",new parameter ="Id") %>
   </th>
   <th>
    <%=Html.ActionLink("Name", "Sort", new  parameter = "Name")%>
   </th>
   <th>
    <%=Html.ActionLink("Status", "Sort", new  parameter = "Status" )%>
   </th>
   <th>
    <%=Html.ActionLink("Notes", "Sort", new  parameter = "Notes")%>
   </th>
  </tr>
  <% foreach (var item in Model) %>

   <tr>
    <td>
     <%= Html.ActionLink("Edit", "Edit", new   id=item.Id ) %> |
    </td>
    <td>
     <%= Html.Encode(item.Id) %>
    </td>
    <td>
     <%= Html.Encode(item.Name) %>
    </td>
    <td>
     <%= Html.Encode(item.Status) %>
    </td>
    <td>
     <%= Html.Encode(item.Notes) %>
    </td> 
   </tr>

  <%  %>   
    </table>

这是做这种事情的唯一方法吗? 如果有人知道不涉及将所有记录一次加载到页面的更好方法,请链接到示例。

【问题讨论】:

@AlteredConcept q 太宽泛了,因为你并没有说你最关心的是什么。是视图(几乎没有,因为它非常简单),使用 linq 以通用方式排序的方式,使用 session 来保存参数,使用类似的“参数”或其解析。 很抱歉。控制器是最困扰我的。我不想在每个控制器中为每个实体列表视图重复所有这些代码。这是很多重复的代码。我试图找出一种可以将其放置在基本控制器中的方法,但运行的是空白。所以我想看看其他人是否有更好更优雅的排序方法 嗯?为什么你的头疼? 【参考方案1】:

查看 DataTables @ DataTables 这将让您对结果进行分页并通过简单的设置进行查询。它适用于 ajax 和 json 数据。看看样品。希望对您有所帮助。

【讨论】:

+1。我已成功在 ASP.NET MVC 应用程序中使用 DataTables jQuery 插件和服务器端处理 (datatables.net/usage/server-side)。 这会在加载时将所有数据加载到页面上(即使它在加载后对数据进行分页)。尝试一次加载 1000 多条记录。页面显示需要一段时间。 使用服务器端处理只发送显示给客户端datatables.net/usage/server-side的行,正如 Anton 指出的那样。 您也可以将其与 PartialView 和返回 JsonResult 的控制器结合使用 你能发布一个如何做到这一点的示例@chris 吗?【参考方案2】:

尝试以下扩展方法(从头开始):

static class OrderByExtender

    public static IOrderedEnumerable<T> OrderBy<T>(this IEnumerable<T> collection, string key, string direction)
    
        LambdaExpression sortLambda = BuildLambda<T>(key);

        if(direction.ToUpper() == "ASC")
            return collection.OrderBy((Func<T, object>)sortLambda.Compile());
        else
            return collection.OrderByDescending((Func<T, object>)sortLambda.Compile());
    

    public static IOrderedEnumerable<T> ThenBy<T>(this IOrderedEnumerable<T> collection, string key, string direction)
    
        LambdaExpression sortLambda = BuildLambda<T>(key);

        if (direction.ToUpper() == "ASC")
            return collection.ThenBy((Func<T, object>)sortLambda.Compile());
        else
            return collection.ThenByDescending((Func<T, object>)sortLambda.Compile());
    

    private static LambdaExpression BuildLambda<T>(string key)
    
        ParameterExpression TParameterExpression = Expression.Parameter(typeof(T), "p");
        LambdaExpression sortLambda = Expression.Lambda(Expression.Convert(Expression.Property(TParameterExpression, key), typeof(object)), TParameterExpression);
        return sortLambda;
    

用法:

var products = Session["Model"] as IEnumerable<Product>() ?? _service.GetAll();

return products.OrderBy("Name", "ASC").ThenBy("Price", "DESC");

假设您一次只使用 1 个 orderby 条件,您可以使用:

var products = Session["Model"] as IEnumerable<Product>();

var sortDirection = Session["Direction"] as string ?? "DESC";
Session["Direction"] = sortDirection == "DESC" ? "ASC" : "DESC";
sortDirection = Session["Direction"] as string;

return products.OrderBy(parameter, sortDirection);

【讨论】:

direction.ToLower() 不应该是 direction.ToUpper() 吗? 正确。感谢您指出这一点,我在记事本中写了这些东西:-) 没问题。我喜欢这种方法,但我遇到了一些问题。有时它会正确排序,有时则不会(而不是升序,而是降序,反之亦然)。 在你的网址中添加一个参数order=DESC/order=ASC。然后在您的前端处理单击标题是否会导致 ASC/DESC 排序。然后你可以像public ActionResult Sort(string parameter, string order)一样排序。【参考方案3】:

如果 JavaScript 被禁用,你就有问题了。

我会选择 noscript 解决方案。

我有两个单选按钮组:

direction:  ( ) ascending    (.) descending

orderBy:  (.) Id   ( ) Name   ( ) Status

我会将 View 视为具有多个提交按钮的 表单

(不带 JavaScript)~~ 两个按钮的名称相同。

在您的 .aspx 页面上,添加三个按钮:

 <input type="submit"    value="Requery"   name="submitButton"/>
 <input type="submit"    value="Previous"  name="submitButton"/>
 <input type="submit"    value="Next"      name="submitButton"/>

在您的控制器中:

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Sort(string direction, string orderBy, string submitButton)

    if (submitButton == "Requery")       //et cetera

TMTOWTDI: 方法不止一种

【讨论】:

【参考方案4】:

我更喜欢这里描述的方法: http://www.c-sharpcorner.com/UploadFile/camurphy/csharpLists03302006170209PM/csharpLists.aspx

所以例如:

var products = new List<Products>();
products = ProductRepository.GetAll();

// Sort Results
products.Sort(
    delegate(Products p1, Products p2) 
    return p1.Name.CompareTo(p2.Name);
);

【讨论】:

你不是说p1.Name.CompareTo(p2.Name)吗?【参考方案5】:

非常喜欢 Jan 的解决方案 - 非常感谢 Jan... 您刚刚为我节省了大约 60 行代码,其中包含解析每个列标题的 case 语句。当与两个会话变量一起使用时,该解决方案“可以进行出色的切换单击,仅按表上的 1 列解决方案排序”,一个用于将 ASC/DESC 保留为布尔值,另一个用于保存类型/列名称。

今天下午我使用了这个 C# 示例扩展并用 VB 实现了它。我设法将一个 30 行的 case 语句缩减为一行代码。

在风景中:

<th>Date <a class="clickable" href="<%=Url.Action("SortStationVisits", New With .SortField = "PlanningDate")%>"><span class="colSort" style="display: inline-table;"></span></a></th>

扩展(公共模块 OrderByExtender):

Imports System.Linq.Expressions

Public Function OrderBy(Of T)(collection As IEnumerable(Of T), key As String, isDescending As Boolean) As IOrderedEnumerable(Of T)
    Dim sortLambda As LambdaExpression = BuildLambda(Of T)(key)
    If isDescending Then
        Return collection.OrderByDescending(DirectCast(sortLambda.Compile(), Func(Of T, Object)))
    Else
        Return collection.OrderBy(DirectCast(sortLambda.Compile(), Func(Of T, Object)))
    End If
End Function

Public Function ThenBy(Of T)(collection As IOrderedEnumerable(Of T), key As String, isDescending As Boolean) As IOrderedEnumerable(Of T)
    Dim sortLambda As LambdaExpression = BuildLambda(Of T)(key)

    If (isDescending) Then
        Return collection.ThenByDescending(DirectCast(sortLambda.Compile(), Func(Of T, Object)))
    Else
        Return collection.ThenBy(DirectCast(sortLambda.Compile(), Func(Of T, Object)))
    End If
End Function

Private Function BuildLambda(Of T)(key As String) As LambdaExpression
    Dim TParameterExpression As ParameterExpression = Expression.Parameter(GetType(T), "p")
    Dim sortLambda As LambdaExpression = Expression.Lambda(Expression.Convert(Expression.[Property](TParameterExpression, key), GetType(Object)), TParameterExpression)
    Return sortLambda
End Function

在控制器操作时:

Public Function SortStationVisits(Optional page As Integer = 1, Optional SortField As String = "") As ActionResult
    Dim sps = LoadSession()

    If SortField = sps.StationVisitSorter Then
        sps.StationVisitDescOrder = Not (sps.StationVisitDescOrder)
    Else
        sps.StationVisitDescOrder = False
    End If

    sps.StationVisitSorter = SortField

    SaveSession(sps)
    Return RedirectToAction("Show")
End Function

在控制器展示方法(1行代码W00T!):

spv.SelectableStationVisits = spv.SelectableStationVisits.OrderBy(sps.StationVisitSorter, sps.StationVisitDescOrder).ToList

【讨论】:

以上是关于在 asp.net MVC 中对表进行排序的主要内容,如果未能解决你的问题,请参考以下文章

使用 ASP.Net 在 SQL 中对表的列值求和时出现异常

在 asp.net mvc 中对控制器进行简单的 Ajax 调用

在asp.net mvc中对控制器进行简单的Ajax调用

如何在 ASP.NET MVC 视图中对数据进行分组?

使用VB在ASP.Net中对GridView中的事件进行排序

Linq 查询在 ASP.NET-Core 3.0 及更高版本中对数字等字符串进行排序