I'm using Entity Framework Core to create an IQueryable. I'd like to find a way to get the results one page at a time (say 10 results at a time), but then expose this as an IEnumerable (or something similar like an IObservable). I also want to ensure that this is as memory-efficient as possible, so in other words, if the page size is 10, then there are only 10 entities sitting in memory at a time. Lastly, I want the database calls to be async, which is what makes this more difficult.
Here's some pseudo code, in which "ToPagingEnumerable" is the method I want to create or use from another library:
IQueryable<T> query = dbContext.SomeTable;
IEnumerable<T> results = query.ToPagingEnumerable(pageSize: 10);
ConvertAndSaveResults(results);
And here's a quick failed attempt, which won't work because you can't combine "yield" with "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();
}
}
I briefly looked at Reactive Streams (https://github.com/reactive-streams/reactive-streams-dotnet), and this seems similar to what I want to accomplish.
I think another option is to use Rx (Reactive) and create an Observable that grabs one page of results from the IQueryable (say 10 rows), feeds them to the Subscriber, then grabs another page (say another 10 rows), and feeds them to the Subscriber.
I just don't know enough about either of these libraries to know how to use them to accomplish my goal, or if there's an easier or different way.