实体通用分页

Entity generic pagination

我必须在一个 table 中查询所有行。一口气,查询太长了,我超时了。所以我想 运行 使用分页分批查询此查询。但是需要做 sizetake orderby。这就是问题所在,如何按通用(可能在主键上)进行排序?或者有没有办法不用 order by ?

public async Task<IEnumerable<T>> GetListBatchLoadingAsync<T>(Expression<Func<T, bool>> iWhere = null, long iSize) where T : class, IEntity
    {
        IQueryable<T> theQueryable = RepositoryDBContext.Set<T>();

        //Where clause
        if (iWhere != null)
            theQueryable = theQueryable.Where(iWhere);

        //batch loading
        Int64 entitiesCount = await theQueryable.CountAsync();
        int totalPage = (int)Math.Ceiling(decimal.Divide(entitiesCount, iSize));

        //query
        var result = new List<T>();
        for (int a = 0; a < totalPage; a++)
             result.AddRange(await  theQueryable.OrderBy(x=>x. ????).Skip(TAKECOUNT * (a)).Take(TAKECOUNT).ToListAsync());

        return result;
    }

假设您有一个主键集(如果您使用的是 EF,则所有表上都应该有),您可以这样做:

var keyProperty = typeof(YourEntityClass).GetProperties().SingleOrDefault(p => p.IsDefined(typeof(KeyAttribute)));

这实际上会查看您的 EF 模型并选择标记为主键的列。如果您使用的是泛型,则可以将 YourEntityClass 替换为您的 T 值。您可以使用 .Name 从 keyProperty 中提取名称,并在您的 orderby 语句中使用它(例如,您可能希望使用扩展的 linq 并指定 propName + " ASC",或者构建一个表达式树)。

或者,您可以使用实体模型的部分 类 来拥有一个接口,例如 IExposesPrimaryKey 并实现一些 returns 主键名称的东西。

我写了一个分页扩展,可能对你有用。具体来说,我认为通用 IOrderedQuerable 说明了如何使 OrderBy 通用:

public static IPagedEntities<T> WithPaging<T>(this IOrderedQueryable<T> orderedQuery, int page, int pageSize)
{
    var totalEntities = orderedQuery.Count();

    var entities = orderedQuery.Skip((page * pageSize)).Take(pageSize);

    return new PagedEntities<T>(page, pageSize, totalEntities, entities);
}

使用方法如下:

// base query
var query = _dbContext.SomeItems.AsQueryable();

var orderedQuery = query.OrderBy(t => t.SomeProperyToOrderBy);

// pages the results
// the WithPaging extension method requires an IOrderedQueryable
// (orderedQuery) which is produced by calling OrderBy on an IQueryable<T>
var withPaging = orderedQuery.WithPaging(yourDesiredPage, yourDesiredPageSize);

IPagedEntities 只是用一些与分页操作相关的额外元数据包装了一个 IEnumerable。它与您的问题关系不大,但为了完整起见,我将其包括在内:

public interface IPagedEntities<out T>
{
    int Page { get; }
    int PageSize { get; }
    int TotalSize { get; }
    int Pages { get; }
    int NumberSkipped { get; }
    int? NextPage { get; }
    int? PriorPage { get; }
    int FirstPage { get; }
    int LastPage { get; }
    bool OnFirstPage { get; }
    bool OnLastPage { get; }
    bool HasNextPage { get; }
    bool HasPreviousPage { get; }

    IEnumerable<T> Entities { get; }
}