C# 通过IQueryable分批枚举
我正在使用实体框架核心创建IQueryable。 我想找到一种方法,一次只获取一个页面的结果(比如一次10个结果),然后将其公开为IEnumerable(或者类似于IObservable的东西)。我还想确保这是尽可能高效的内存,换句话说,如果页面大小是10,那么一次内存中只有10个实体。最后,我希望数据库调用是异步的,这使得这更困难 下面是一些伪代码,其中“ToPagingEnumerable”是我想从另一个库中创建或使用的方法:C# 通过IQueryable分批枚举,c#,entity-framework,system.reactive,C#,Entity Framework,System.reactive,我正在使用实体框架核心创建IQueryable。 我想找到一种方法,一次只获取一个页面的结果(比如一次10个结果),然后将其公开为IEnumerable(或者类似于IObservable的东西)。我还想确保这是尽可能高效的内存,换句话说,如果页面大小是10,那么一次内存中只有10个实体。最后,我希望数据库调用是异步的,这使得这更困难 下面是一些伪代码,其中“ToPagingEnumerable”是我想从另一个库中创建或使用的方法: IQueryable<T> query = dbCo
IQueryable<T> query = dbContext.SomeTable;
IEnumerable<T> results = query.ToPagingEnumerable(pageSize: 10);
ConvertAndSaveResults(results);
IQueryable query=dbContext.SomeTable;
IEnumerable results=query.topagineNumerable(页面大小:10);
ConvertAndSaveResults(结果);
这里有一个快速失败的尝试,它不会起作用,因为您不能将“yield”与“async”结合起来:
公共静态IEnumerable ToPagingEnumerable(
这是可靠的消息来源,
整数大小)
{
var-skip=0;
var cached=wait source.Take(size.ToListAsync();
while(cached.Any())
{
foreach(缓存中的var项)
{
收益回报项目;
}
skip+=cached.Count;
cached=wait source.Skip(Skip).Take(size.toListSync();
}
}
我简要地看了一下反应流(),这似乎与我想要完成的类似
我认为另一种选择是使用Rx(反应式)并创建一个可观察对象,从IQueryable中获取一页结果(比如10行),将其提供给订阅者,然后获取另一页(比如另外10行),并将其提供给订阅者
我只是对这两个库都不太了解,不知道如何使用它们来实现我的目标,或者是否有更简单或不同的方法。您好,您可以使用此扩展方法
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 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;
}
公共异步任务GetAllPagedAsync(PagingSettings请求),其中tentityTo:class
{
var projectTo=Set();//这是DBSet
var entityDtos=projectTo.OrderByField(新的排序设置());
if(request.PagingSettings!=null)
entityDtos=entityDtos.ToPage(请求.分页设置);
var resultItems=await entityDtos.ToListAsync();
var result=MakeSimplePagedResult(request.PagingSettings,resultItems);
返回结果;
}
结果是什么
public class SimplePagedResult<T>
{
public IEnumerable<T> Results { get; set; }
public int CurrentPage { get; set; }
public int PageSize { get; set; }
}
公共类SimplePagedResult
{
公共IEnumerable结果{get;set;}
public int CurrentPage{get;set;}
公共int PageSize{get;set;}
}
为什么要多次运行查询
那就:
var results = source.ToAsyncEnumerable().Buffer(10);
以下是一种不使用扩展方法成批处理
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;
}
这个答案对你有帮助吗?我希望数据库调用是异步的,但如果从一个上下文使用
IQueryable
,您将无法并行运行这些调用。
var results = source.ToAsyncEnumerable().Buffer(10);
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;
}
var myqueryable = // GetQueryable();
//var pageCount = (int)Math.Ceiling(myqueryable.Count() * 1D / PageSize);
int skip = PageNumber * PageSize - PageSize;
return myqueryable.Skip(skip).Take(PageSize);