代码之家  ›  专栏  ›  技术社区  ›  rball

如何使用LINQ按多个字段排序?

  •  21
  • rball  · 技术社区  · 15 年前

    我正在创建一个模拟数据源,我希望能够传入SortExpressions的列表。

    public SortExpression(string name, SortDirection direction)
    {
         this.name = name;
         this.direction = direction;
    }
    

    更新 还有乔恩·斯基特的代码,还有整个班级。getData()只是用x个记录数填充对象。

    public class Data
    {
    
    public int Id { get; set; }
    public Guid gId { get; set; }
    public string Name { get; set; }
    public string Phone { get; set; }
    public string Address { get; set; }
    public DateTime Created { get; set; }
    public string SortMe { get; set; }
    public static List<Data> GetFakeData(int start, int numberToFetch, IList<SortExpression> sortExpressions, IList<FilterExpression> filterExpressions, out int totalRecords)
    {
        DataCollection items = GetData();
        IEnumerable<Data> query = from item in items select item;
    
        bool sortExpressionsExist = sortExpressions != null;
        if (sortExpressionsExist)
        {
            // Won't be read in the first iteration; will be written to
            IOrderedEnumerable<Data> orderedQuery = null;
            for (int i = 0; i < sortExpressions.Count; i++)
            {
                // Avoid single variable being captured: capture one per iteration.
                // Evil bug which would be really hard to find :)
                int copyOfI = i;
                // Tailor "object" depending on what GetProperty returns.
                Func<Data, object> expression = item =>
                      item.GetType().GetProperty(sortExpressions[copyOfI].Name);
    
                if (sortExpressions[i].Direction == SortDirection.Ascending)
                {
                    orderedQuery = (i == 0) ? query.OrderBy(expression)
                                            : orderedQuery.ThenBy(expression);
                }
                else
                {
                    orderedQuery = (i == 0) ? query.OrderByDescending(expression)
                                            : orderedQuery.ThenByDescending(expression);
                }
            }
            query = orderedQuery;
        }
    
        bool filterExpressionsExist = filterExpressions != null;
        if (filterExpressionsExist)
        {
            foreach (var filterExpression in filterExpressions)
            {
                query.Where(item => item.GetType().GetProperty(filterExpression.ColumnName).GetValue(item, null).ToString().Contains(filterExpression.Text));
            }
        }
        totalRecords = query.Count();
    
    
           return query.Skip(start).Take(numberToFetch).ToList<Data>();
        }
    }
    

    好像什么都没做。编译,没有错误,只是没有排序。有什么想法吗?

    6 回复  |  直到 11 年前
        1
  •  27
  •   Jon Skeet    15 年前

    有两个问题。第一个是其他人提到的-您需要使用返回的值 OrderBy 等等,第二个是每次你打电话 排序 ,这将添加一个新的“主要”排序。你真的想要 ThenBy 第一次订购后。不幸的是,这让它很难看。经过重构后,它仍然很难看,但不是 坏的…

    IEnumerable<Data> query = from item in items select item;
    if (sortExpressionsExist)
    {
        // Won't be read in the first iteration; will be written to
        IOrderedEnumerable<Data> orderedQuery = null;
        for (int i = 0; i < sortExpressions.Count; i++)
        {
            // Avoid single variable being captured: capture one per iteration.
            // Evil bug which would be really hard to find :)
            int copyOfI = i;
            // Tailor "object" depending on what GetProperty returns.
            Func<Data, object> expression = item => 
                  item.GetType()
                      .GetProperty(sortExpressions[copyOfI].Name)
                      .GetValue(item, null);
    
            if (sortExpressions[i].Direction == SortDirection.Ascending)
            {
                orderedQuery = (i == 0) ? query.OrderBy(expression)
                                        : orderedQuery.ThenBy(expression);
            }
            else
            {
                orderedQuery = (i == 0) ? query.OrderByDescending(expression)
                                        : orderedQuery.ThenByDescending(expression);
            }
        }
        query = orderedQuery;
    }
    
        2
  •  5
  •   Gennady Vanin Геннадий Ванин Mikael Svenson    11 年前

    orderby返回新的IEnumerable,因此需要执行以下操作:

    IEnumerable<Data> results 
        = query.OrderBy(item => item.GetType().GetProperty(sortExpressions[i].Name));
    
        3
  •  2
  •   JP Alioto    15 年前

    OrderBy on IEnumerable 返回IORDerenumerable。它不会按行对它们进行排序。所以从你的.orderby中获取返回值,你就可以了。

        4
  •  2
  •   Ruben Bartelink    15 年前

    orderby/orderbyDescending“operators”的工作方式与string.toupper()类似,即,它们接受您调用它的对象,并生成一个具有您请求的内容的“copy”。

    换句话说,不是说:

    query.Orderby(item->item.X)
    

    你应该做

    query = query.Orderby(item->item.X)
    

    sortedResult = query.Orderby(item->item.X)
    

    [正如乔恩·斯基特指出的,使用 ThenBy / ThenByDescending 在他的回答中]

        5
  •  2
  •   VoodooChild    14 年前

    查询不可变,因此orderby返回一个新对象。您需要进行相同的调用,但在开头添加“query=”即可。

    query = query.OrderBy(item => item.GetType().GetProperty(sortExpressions[i].Name));
    
        6
  •  1
  •   Nalan Madheswaran    11 年前

    这将起作用:

    YourCollection.Orderby(item => item.Property1).ThenBy(item => item.Property2);