2017-10-05 9 views
2

私はEntity Framework Coreを使用してIQueryableを作成しています。 私は結果を一度に1ページ(一度に10件の結果)とするが、これをIEnumerable(またはIObservableのようなもの)として公開する方法を見つけたい。私はまた、これができるだけメモリ効率的であることを保証したい、つまりページサイズが10であれば、一度にメモリに座っているエンティティは10個だけです。最後に、データベース呼び出しを非同期にすることが必要です。これがこれを難しくしています。バッチでIQueryableを列挙します。

ここで「ToPagingEnumerableは」私が別のライブラリから作成または使用する方法であるいくつかの擬似コード、です:

IQueryable<T> query = dbContext.SomeTable; 
IEnumerable<T> results = query.ToPagingEnumerable(pageSize: 10); 
ConvertAndSaveResults(results); 

そして、ここで「あなたができるので、動作しません迅速に失敗した、ですが、 T「非同期」と「利回り」コンバイン:

public static IEnumerable<TSource> ToPagingEnumerable<TSource>(
    this IQueryable<TSource> source, 
    int size) 
{ 
    var skip = 0; 
    var cached = await source.Take(size).ToListAsync(); 
    while (cached.Any()) 
    { 
     foreach (var item in cached) 
     { 
      yield return item; 
     } 
     skip += cached.Count; 
     cached = await source.Skip(skip).Take(size).ToListAsync(); 
    } 
} 

を私は簡単に反応小川(https://github.com/reactive-streams/reactive-streams-dotnet)を見て、これは私が達成したいものに似ているようです。

もう1つの選択肢は、Rx(Reactive)を使用して、IQueryableから結果の1ページ(たとえば10行)を取得し、サブスクライバにフィードし、別のページ(別の10行)それらを加入者に供給する。

私の目標を達成するためにこれらのライブラリを使用する方法を知っているか、より簡単かどうかを知るために、これらのライブラリのいずれかについて十分に知りません。

+0

は、この答えはすべてであなたを助けていますか? https://stackoverflow.com/questions/40995248/asynchronous-paging-with-entity-framework-6-1-3 –

+0

*データベースコールを非同期にすることはできますが、1つのコンテキストからのIQueryableを使用しますこれらの呼び出しを並行して実行することはできません。 –

答えて

0

こんにちはあなたはこの拡張メソッド

public static class QuerableExtensions 
{ 
    public static IQueryable<TEntity> ToPage<TEntity>(this IQueryable<TEntity> query, PagingSettings pagingSettings) where TEntity : class 
    { 
     if (pagingSettings != null) 
     { 
      return query.Skip((pagingSettings.PageNumber - 1)*pagingSettings.PageSize).Take(pagingSettings.PageSize); 
     } 
     return query; 
    } 
    public static IQueryable<T> OrderByField<T>(this IQueryable<T> query, SortingSettings sortingSettings) 
    { 
     var exp = PropertyGetterExpression<T>(sortingSettings); 

     var method = sortingSettings.SortOrder.Equals(SortOrder.Asc) ? "OrderBy" : "OrderByDescending"; 

     var types = new[] { query.ElementType, exp.Body.Type }; 

     var callExpression = Expression.Call(typeof(Queryable), method, types, query.Expression, exp); 
     return query.Provider.CreateQuery<T>(callExpression); 
    } 


} 

public class PagingSettings 
{ 
    public PagingSettings() 
     : this(50, 1) 
    { } 

    protected PagingSettings(int pageSize, int pageNumber) 
    { 
     PageSize = pageSize; 
     PageNumber = pageNumber; 
    } 

    public int PageNumber { get; set; } 
    public int PageSize { get; set; } 
} 

そして、このようにそれを使用するために使用することができますし、ページング

 public async Task<SimplePagedResult<TEntityDto>> GetAllPagedAsync<TEntityDto>(PagingSettins request) where TEntityDto : class 
    { 
     var projectTo = Set(); // Here is DBSet<TEnitity> 


     var entityDtos = projectTo.OrderByField(new SortingSettings()); 

     if (request.PagingSettings != null) 
      entityDtos = entityDtos.ToPage(request.PagingSettings); 

     var resultItems = await entityDtos.ToListAsync(); 

     var result = MakeSimplePagedResult(request.PagingSettings, resultItems); 
     return result; 
    } 

を作る前に、あなたのセットを注文しなければならず、結果のクラスは

public class SimplePagedResult<T> 
{ 
    public IEnumerable<T> Results { get; set; } 
    public int CurrentPage { get; set; } 
    public int PageSize { get; set; } 
} 
0

なぜクエリを複数回実行しますか?

方法についてちょうど:

var results = source.ToAsyncEnumerable().Buffer(10); 
関連する問題