【问题标题】:IOrderedQueryable Skip and TakeIOrderedQueryable 跳过和采取
【发布时间】:2014-02-04 11:53:11
【问题描述】:

我的所有存储库都继承自以下抽象类:

abstract class RepositoryBase<T> {
    void Add();
    void Delete();
    void SaveChanges();
}

我想添加另一种方法来自动分页 IQueryable&lt;T&gt; 并从结果中返回 List&lt;T&gt;

protected List<T> Paginate(IQueryable<T> content, int? skip, int? take)
{
    if (skip.HasValue) content = content.Skip(skip.Value);
    if (skip.HasValue && take.HasValue) content = content.Take(take.Value);
    return content.ToList();
}

但是,Skip 需要IOrderedQueryable&lt;T&gt; 的来源。我尝试将方法签名更改为:

Paginate(IOrderedQueryable<T> content, int? skip, int? take)

但是Skip 返回一个IQueryable&lt;T&gt; 所以我收到错误Cannot convert source type 'System.Linq.IQueryable&lt;T&gt;' to target type 'System.Linq.IOrderedQueryable&lt;T&gt;'

如何强制实现类向我的方法发送IOrderedQueryable&lt;T&gt; 并让我的分页方法工作?

【问题讨论】:

  • Skip 的哪个版本要求(在编译时)源是IOrderedQueryableQueryable.Skip 不...
  • @JonSkeet LINQ to Entites - The method 'Skip' is only supported for sorted input in LINQ to Entities. The method 'OrderBy' must be called before the method 'Skip' - 除非我误解了错误。
  • 这很奇怪 - 因为如果你有 using System.Linq; 它应该采用这种方法 - msdn.microsoft.com/en-us/library/bb357513(v=vs.110).aspx
  • 附带说明,如果我打电话给Paginate(query, null, 20) 并且它没有应用,我会觉得很奇怪。我不认为第二行的 skip.HasValue 检查是直观或明显的。
  • @RGraham 确认:您可以使用Take 而不使用Skip

标签: c# linq entity-framework-5 iqueryable


【解决方案1】:

听起来您可能想让Paginate 仍然使用IOrderedQueryable&lt;T&gt; 以在编译时验证您已经从订购的东西开始 - 但您当时没有需要分配回相同的变量。例如:

protected List<T> Paginate(IOrderedQueryable<T> content, int? skip, int? take)
{
    // Different variable type so that we can assign to it below...
    IQueryable<T> result = content;
    if (skip.HasValue) result = result.Skip(skip.Value);
    if (skip.HasValue && take.HasValue) result = result.Take(take.Value);
    return result.ToList();
}

正如 Marc 所说,最好将 Take 行更改为:

if (take.HasValue) result = result.Take(take.Value);

【讨论】:

  • 只是为了使事情复杂化:一些其他提供者确实要求原始查询具有明确的顺序......所有的乐趣和游戏;如果没有OrderBy / IOrderedQueryable&lt;T&gt;,它可以与 L2S 一起正常工作
  • 我将此标记为答案,因为我希望 Repository 实现准确地表示结果集的顺序,因此将签名更新为 IOrderedQueryable&lt;T&gt; 是有意义的
  • @MarcGravell:我想说在内部 API 中强制执行这个无论如何都是个好主意 - 即使你 可以 以任意顺序跳过,也可能不是一个好主意:)
【解决方案2】:

Queryable.SkipQueryable.Take 方法不需要这个,但是一些提供者(我主要认为“EF”)确实坚持这样做;在这种情况下,解决方案很简单:确保原始查询有顺序。例如:

var query = {whatever}.OrderBy(x => x.Id); // identity column? why not...
var page = Paginate(query, ...);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-03-01
    • 2012-06-21
    • 1970-01-01
    • 2017-07-27
    • 2011-04-21
    • 2011-07-18
    • 2015-08-28
    • 1970-01-01
    相关资源
    最近更新 更多