如何使用Linq To Entities处理分页IQueryable?(OrderBy问题)

3

我正在使用Linq to Entities构建一个简单的ASP.NET MVC网站。我的第一次尝试是Nerd Dinner,那里有我尝试使用的分页列表代码。代码如下:

public class PaginatedList<T> : List<T>
{

    public int PageIndex { get; private set; }
    public int PageSize { get; private set; }
    public int TotalCount { get; private set; }
    public int TotalPages { get; private set; }

    public PaginatedList(IQueryable<T> source, int pageIndex, int pageSize)
    {
        PageIndex = pageIndex;
        PageSize = pageSize;
        TotalCount = source.Count();
        TotalPages = (int)Math.Ceiling(TotalCount / (double)PageSize);

        this.AddRange(source.Skip(PageIndex * PageSize).Take(PageSize));
    }

    public bool HasPreviousPage
    {
        get
        {
            return (PageIndex > 0);
        }
    }

    public bool HasNextPage
    {
        get
        {
            return (PageIndex + 1 < TotalPages);
        }
    }
}

问题在于我正在使用实体框架,上面的代码会抛出以下错误:

方法“Skip”仅支持已排序的输入,适用于LINQ to Entities。 必须在方法“Skip”之前调用方法“OrderBy”。

不了解Linq的细节,当我不知道上述方法中列名是什么时,我不确定如何添加orderby子句,因为它是通用的。

谢谢!

4个回答

9

首先,我强烈建议使用免费的PagedList代码而不是编写自己的代码,因为它考虑了许多你最终必须自己发现的事情,并且几乎没有缺点。

回答你的问题,你应该在将列表传递给分页函数之前对其进行排序。如果你需要动态执行此操作,可以使用Microsoft DynamicQuery库。但通常,调用代码将知道如何对列表进行排序。


1
感谢您发布关于PagedList的内容(最好不要重复造轮子)。 - Eric Labashosky

6

你可以更改构造函数的签名,要求传入一个IOrderedQueryable<T>参数,而不是IQueryable<T>。调用代码将负责处理排序。

public PaginatedList(IOrderedQueryable<T> source, int pageIndex, int pageSize)

4
我认为最好的方法是在将查询传递给“PaginatedList”之前,确保它们有一个顺序。

2
你可以向该方法添加另一个参数,以允许调用者定义OrderBy子句。
public PaginatedList(IQueryable<T> source, Func<T, TKey> orderBy, 
    int pageIndex, int pageSize)
{
    // your other code here
    this.AddRange(source.OrderBy(orderBy)
        .Skip(pageIndex * pageSize)
        .Take(pageSize));
}

我尝试了你的答案,但是出现了“找不到'TKey'类型或命名空间名称(是否缺少使用指令或程序集引用?)”的错误。 - Amir Ismail

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接