【问题标题】:C# Reverse IQueryableC# 反向 IQueryable
【发布时间】:2019-01-27 21:32:34
【问题描述】:

我正在从另一种方法 (QueryItems) 中检索已订购的 IQueryable<Item>。我想(有条件地)在传递IQueryable<Item> 之前颠倒它的顺序。

public async Task<PagedList<Item>> GetItems(FilterParameters filterParameters)
{
    var items = QueryItems(filterParameters)

    if (filterParams.Descending)
    {
        //do something to reverse the order of the IQueryable
    }

    return await PagedList<Item>
        .CreateAsync(items, filterParams.PageNumber, filterParams.PageSize)
}

我不能这样做 var reversed = items.ToList().Reverse; items = reversed.AsQueryable() 因为那样它(显然)不能用于异步任务。

当我尝试执行 items = items.Reverse() 时,出现以下错误:

System.NotImplementedException: Remotion.Linq.Clauses.ResultOperators.ReverseResultOperator

主要是因为我很懒,我宁愿不使用QueryItems 方法来实现items.OrderByDescending(),因为这需要一堆if/else 语句。

那么...如何反转 IQueryable 的顺序?

编辑 - 包括 PagedList.CreateAsync(...)

public class PagedList<T> : List<T>
{
    public int CurrentPage { get; set; }
    public int TotalPages { get; set; }
    public int PageSize { get; set; }
    public int TotalCount { get; set; }

    public PagedList(List<T> items, int count, int pageNumber, int pageSize)
    {
        TotalCount = count;
        PageSize = pageSize;
        CurrentPage = pageNumber;
        TotalPages = (int) Math.Ceiling(count / (double) pageSize);
        this.AddRange(items);
    }

    public static async Task<PagedList<T>> CreateAsync(IQueryable<T> source, int pageNumber, int pageSize)
    {
        var count = await source.CountAsync();
        var items = await source.Skip((pageNumber - 1) * pageSize).Take(pageSize).ToListAsync();
        return new PagedList<T>(items, count, pageNumber, pageSize);
    }
}

【问题讨论】:

  • 您可以将外部OrderByDescending 附加到QueryItems 返回的内容上,但从性能的角度来看这可能并不好,并且您需要全面了解QueryItems 无论如何应用的排序级别。所以你需要一堆Ifs,在你最初应用排序的地方。
  • 这基本上是关于实现集合和 IQueryable 之间的区别。
  • 为什么不能使用 .OrderByDescending()
  • @Seabizkit 在我的QueryItems 方法中,我已经在订购列表了。如果我执行类似 `items = items.OrderByDescending(item => item.Id) 的操作,那么我在前一个方法中所做的排序将被覆盖。我真的只是想在它已经被订购后寻找一种简单的方法来翻转它。

标签: c# linq asp.net-core-2.1


【解决方案1】:

正如下面的 cmets 所指出的,您几乎可以肯定想要颠倒整个查询的顺序,以便最后一页成为第一页,反之亦然。为此,您别无选择,只能使用OrderByDescending。但是,您可以将实际 order by 子句分解,以减少代码重复。例如:

Expression<Func<Item,int>> orderBy = o => o.Id;

注意:上面的int 类型参数对应于表达式中属性的类型。根据您实际订购的内容,相应地更改右侧的 Id 和左侧的 int

然后:

items = filterParams.Descending
    ? items.OrderByDescending(orderBy)
    : items.OrderBy(orderBy);

【讨论】:

  • 这不是一个坏主意。让我编辑我的问题以显示PagedList.CreateAsync 方法。我可能会在返回的页面列表的items 属性上执行Reverse()。 (顺便说一句,我没有否决你的答案)
  • 所以,是的。你可以直接打电话给pagedList.Reverse(),因为你的PagedList&lt;T&gt;只是一个List&lt;T&gt;
  • @JED,你不需要完整的查询而不是页面,否则你只是得到有序的页面,如果你要反转你可能想要获取最后一个的项目页面?
  • @johnny5:哦。好点子。我只是专注于能够扭转项目,并没有考虑整体意图。如果您需要在查询本身中反转顺序,那么您唯一的选择是分支并改用OrderByDescending
  • @ChrisPratt Branching for OrderByDescending 可能是要走的路,但是如果他们只是将总页数添加到 Page 类并反转页面并执行反向操作,这仍然可以工作同样的影响。
【解决方案2】:

编写一个ExpressionVisitor 并使用InterceptedQuery 将所有OrderByThenBy 重写为OrderByDescendingThenByDescending 怎么样?反之亦然?

【讨论】:

  • 这似乎有点过头了,因为他们可以在创建查询时添加一两个 if 语句
  • 我尽量不假设原始问题解释了所有未回答的原因可能是最好的解决方案。如果查询创建由第三方完成或提供的代码无法更改怎么办?
  • 好点,我不知道他们在内部使用什么,但无论他们使用什么,这都会起作用
猜你喜欢
  • 1970-01-01
  • 2015-08-27
  • 2023-03-06
  • 2013-04-16
  • 2011-01-15
  • 2016-12-15
  • 1970-01-01
  • 1970-01-01
  • 2020-09-23
相关资源
最近更新 更多