我正在尝试在ASP.NET核心中实现一个控制器,它返回从SQL数据库查询的潜在的大量数据。为此,我使用buffered: false参数通过Dapper的Query()方法执行查询。这意味着必须在枚举查询结果之后释放SqlConnection对象。
似乎没有一种简单的方法来实现这一点。我通过编写一个包装IEnumerable的类来让它正常工作,reference计算它被要求创建的任何枚举数。当所有枚举器都被释放后,它就会释放数据库连接。
这似乎是可行的,但我担心在某些情况下,数据库连接不会被释放(例如,如果请求在开始枚举查询结果之前被取消)。除了写入临时文件并将其流式传输到客户端之外,还有更好的方法吗?
发布于 2018-12-07 16:27:17
这就是我最后想出来的。连接的生存期归代替通常的ObjectResult返回的StreamedDatabaseObjectResult所有。repository类返回要处置的连接以及结果。这似乎涵盖了所有的情况,并且很好地使用了异步方法。
public class StreamedDatabaseObjectResult : ActionResult
{
private readonly Func<Task<DisposableEnumerable>> _getValuesFunc;
public StreamedDatabaseObjectResult(Func<Task<DisposableEnumerable>> getValuesFunc)
{
_getValuesFunc = getValuesFunc;
}
public override async Task ExecuteResultAsync(ActionContext context)
{
using (var de = await _getValuesFunc())
{
var objectResult = new ObjectResult(de.Values);
await objectResult.ExecuteResultAsync(context);
}
}
}
public class DisposableEnumerable : IDisposable
{
public IEnumerable Values { get; }
private readonly IDisposable _disposable;
public DisposableEnumerable(IDisposable disposable, IEnumerable values)
{
Values = values;
_disposable = disposable;
}
/// <inheritdoc />
public void Dispose()
{
_disposable.Dispose();
}
}
[HttpGet]
[ProducesResponseType(200)]
public ActionResult<IEnumerable<MyClass>> GetThings(CancellationToken cancellationToken)
{
return new StreamedDatabaseObjectResult(() => _repo.GetThings(cancellationToken));
}
https://stackoverflow.com/questions/53671603
复制