我正在使用Entity Framework Core来创建IQueryable。 我想找到一种方法一次一页地获得结果(一次说10个结果),但随后将其公开为IEnumerable(或类似于IObservable的东西)。我还想确保尽可能保持内存效率,换句话说,如果页面大小为10,那么一次只有10个实体驻留在内存中。最后,我希望数据库调用是异步的,这使得这更加困难。
这是一些伪代码,其中“ToPagingEnumerable”是我想要从另一个库创建或使用的方法:
IQueryable<T> query = dbContext.SomeTable;
IEnumerable<T> results = query.ToPagingEnumerable(pageSize: 10);
ConvertAndSaveResults(results);
这是一个快速失败的尝试,由于你无法将“yield”与“async”结合起来,因此无效:
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();
}
}
我简要介绍了Reactive Streams(https://github.com/reactive-streams/reactive-streams-dotnet),这看起来与我想要实现的相似。
我认为另一个选择是使用Rx(Reactive)并创建一个Observable,它从IQueryable(比如10行)中抓取一页结果,将它们提供给订阅者,然后抓取另一个页面(比如另外10行),并将它们提供给订阅者。
我对这两个库中的任何一个都不太了解,知道如何使用它们来实现我的目标,或者是否有更简单或不同的方式。
答案 0 :(得分: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; }
}
答案 1 :(得分:0)
为什么多次运行查询?
如何:
results['CreationDate'] = list(pd.to_datetime(pd.Series(strtotime)))
答案 2 :(得分:0)
这是一种无需使用扩展方法即可批量处理您的 IQueryable
的方法:
var batchSize = 5000;
var myqueryable = // GetQueryable();
var count = myqueryable.Count();
var processed = 0;
while (processed < count)
{
var take = batchSize <= count - processed ? batchSize : count - processed;
var batchToProcess = myqueryable.Skip(processed).Take(take);
//Do your processing, insert, what have you...
processed += take;
}
或者您可以简单地指定 PageSize 和 PageNumber,如下所示:
var myqueryable = // GetQueryable();
//var pageCount = (int)Math.Ceiling(myqueryable.Count() * 1D / PageSize);
int skip = PageNumber * PageSize - PageSize;
return myqueryable.Skip(skip).Take(PageSize);