如何以正确的方式取消异步查询

时间:2013-08-06 11:52:05

标签: c# .net wpf entity-framework entity-framework-6

这是this question的后续问题。

我试图从我的数据库加载数据需要5-10秒,但我希望GUI能够保持响应,并且它应该是可以取消的。

private CancellationTokenSource _source;

public IEnumerable<Measurement> Measurements { get { ... } set { ... } }

private async void LoadData()
{
    _source = new CancellationTokenSource();

    using (var context = new TraceContext())
    {
        Measurements = null;
        Measurements = await context.Measurements.ToListAsync(_source.Token);
    }
}

private void Cancel()
{
    if (_source != null)
        _source.Cancel();
}

public RelayCommand ReloadCommand
{
    get { return _reloadCommand ?? (_reloadCommand = new RelayCommand(Reload)); }
}
private RelayCommand _reloadCommand;

public RelayCommand CancelCommand
{
    get { return _cancelCommand ?? (_cancelCommand = new RelayCommand(Cancel)); }
}
private RelayCommand _cancelCommand;

我已经尝试了一些事情,但是我无法让它正常工作,这只是加载了List而这就是全部,我无法取消它。

这个错误在哪里?

1 个答案:

答案 0 :(得分:4)

感谢你提出这个问题。目前,EF中此异步API的实现依赖于底层ADO.NET提供程序来取消,但SqlDataReader.ReadAsync有一些限制,我们观察到在许多情况下,在请求取消时不会立即取消。我们正在考虑修复EF6 RTM中的a bug,这是关于在EF方法内的行读取之间引入我们自己的取消请求的检查。

同时,您可以使用ForEachAsync()将项目添加到列表并检查每一行,例如,您可以解决此限制。 (未经过彻底测试):

    public async static Task<List<T>> MyToListAsync<T>(
        this IQueryable<T> source,
        CancellationToken token)
    {
        token.ThrowIfCancellationRequested();
        var list = new List<T>();
        await source.ForEachAsync(item =>
        {
            list.Add(item);
            token.ThrowIfCancellationRequested();
        });
        return list;
    }