2015-06-16 2 views
2

Я должен запросить все строки в одной таблице. За один раз запрос слишком длинный, я получаю таймаут. Поэтому я хочу запустить этот запрос в нескольких партиях, используя разбивку на страницы. Но делать size и take orderby не требуется. И в этом проблема, как сделать заказ родовым (возможно, на первичном ключе)? Или есть способ без заказа?Сущность родовое разбиение на страницы

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; 
    } 

ответ

0

Я написал расширение поискового вызова, которое может быть вам полезна. В частности, я думаю, что общий 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); 

The 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; } 
} 
+0

спасибо за ответ. Но моя самая большая проблема заключается в том, чтобы задать порядок выбора ключа в общем виде. – Julian50

1

Если у вас есть первичный набор ключей (который вы должны иметь на всех таблицах, если вы используете EF), вы можете сделать это:

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

Это по существу будет смотреть на модели EF и выберите столбец, помеченный как первичный ключ. Вы можете заменить YourEntityClass значением T, если вы используете дженерики. Вы можете вывести это имя из keyProperty с помощью .Name и использовать его в инструкции orderby (вы можете использовать расширенный linq и указать, например, propName + " ASC" или построить дерево выражений).

В качестве альтернативы вы можете использовать классы Partial вашей модели сущности, чтобы иметь такой интерфейс, как IExposesPrimaryKey, и реализовать что-то, возвращающее имя первичного ключа.

+0

Как насчет составных первичных ключей? – DavidG

+0

Я понимаю, как вы извлекаете propertyInfo ключа, но как его использовать в orderby? Как преобразовать его в keyselector? – Julian50

+0

@ Julian50: Вы можете либо построить дерево выражений с нуля, либо использовать библиотеку типа [dynamic LINQ] (https://dynamiclinq.codeplex.com/), чтобы упростить ее. – StriplingWarrior

Смежные вопросы