我们使用IEnumerables从数据库中返回大量数据集:
public IEnumerable<Data> Read(...)
{
using(var connection = new SqlConnection(...))
{
// ...
while(reader.Read())
{
// ...
yield return item;
}
}
}
Run Code Online (Sandbox Code Playgroud)
现在我们想使用异步方法来做同样的事情.但是,async没有IEnumerables,因此我们必须将数据收集到列表中,直到加载整个数据集:
public async Task<List<Data>> ReadAsync(...)
{
var result = new List<Data>();
using(var connection = new SqlConnection(...))
{
// ...
while(await reader.ReadAsync().ConfigureAwait(false))
{
// ...
result.Add(item);
}
}
return result;
}
Run Code Online (Sandbox Code Playgroud)
这将消耗服务器上的大量资源,因为所有数据必须在返回之前在列表中.IEnumerables处理大数据流的最佳且易于使用的异步替代方法是什么?我想避免在处理时将所有数据存储在内存中.
我使用dapper将数据库中的对象作为IEnumerable返回.默认dapper的缓冲区设置为true.
这是如何运作的?
如果dapper缓存第一个查询,然后从内存中获取对象.
如果有人在表中编辑/删除/添加行会发生什么.必须再次为此查询重新缓存所有数据吗?
我们最近将使用的 ASP.NET Core API 迁移Dapper到 .NET Core 3.1。迁移后,我们觉得有机会为我们的一个端点使用最新IAsyncEnumerable功能C# 8。
这是更改前的伪代码:
public async Task<IEnumerable<Item>> GetItems(int id)
{
var reader = await _connection.QueryMultipleAsync(getItemsSql,
param: new
{
Id = id
});
var idFromDb = (await reader.ReadAsync<int?>().ConfigureAwait(false)).SingleOrDefault();
if (idFromDb == null)
{
return null;
}
var items = await reader.ReadAsync<Item>(buffered: false).ConfigureAwait(false);
return Stream(reader, items);
}
private IEnumerable<Item> Stream(SqlMapper.GridReader reader, IEnumerable<Item> items)
{
using (reader)
{
foreach (var item in items)
{
yield return item;
}
}
}
Run Code Online (Sandbox Code Playgroud)
之后 …