2017-10-05 131 views
2

我正在使用实体框架核心创建一个IQueryable。 我想找到一次获得结果一页的方法(一次说10个结果),但是然后将其作为IEnumerable(或类似IObservable之类的东西)公开。我也想确保这是尽可能的高效内存,换句话说,如果页面大小为10,那么每次只有10个实体坐在内存中。最后,我希望数据库调用是异步的,这是更加困难的原因。批量枚举通过IQueryable

下面是一些伪代码,其中“ToPagingEnumerable”是,我想创建或从其他图书馆使用方法:

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

而且这里有一个快速失败的尝试,这是行不通的,因为你可以”牛逼结合“产量”与“异步”:

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),这似乎类似于我要完成。

我认为另一种选择是使用Rx(Reactive)并创建一个Observable,从IQueryable抓取一页结果(比如10行),将它们提供给订阅服务器,然后抓取另一个页面(比如说10行) ,并将它们提供给订阅者。

我只是不太了解这些库中的任何一个知道如何使用它们来实现我的目标,或者如果有更简单或不同的方式。

+0

这是否回答帮你呢? https://stackoverflow.com/questions/40995248/asynchronous-paging-with-entity-framework-6-1-3 –

+0

*我想数据库调用是异步*确定,但从一个上下文中的'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);