取消长时间运行的实体框架6异步请求

时间:2015-08-14 18:24:48

标签: c# wpf entity-framework asynchronous

我在WPF应用程序中使用实体框架6(DbContext),我想找到一种方法来正确取消async数据加载方法(ToListAsync& ; FirstOrDefaultAsync)所以我可以立即开始另一个请求。

我一直在努力坚持每个表单的单个上下文(在我的情况下是tab)标准,到目前为止,我一直在通过确保UI被禁用来处理这些调用的非线程安全性质在请求期间,用户无法在进行任何新请求时启动任何新请求。但是,我现在遇到一个用例,这是不可能的。我需要在一些长时间运行的请求中保持UI响应,为了做到这一点,我需要一种方法来取消当前请求并立即启动另一个请求。

我尝试利用添加到CancellationToken方法的Async支持,但我发现当我取消请求时,它实际上并没有取消任何内容。它会正确抛出OperationCanceledException,但请求仍在进行中,当我尝试再发出请求后,我仍然会NotSupportedException (A second operation started on this context...)

我正在使用更改跟踪,因此更改应用以针对每个请求使用新的上下文是不现实的。

此外,我暂时通过处理当前上下文并在每次特定视图模型在一个已经在进行中发出请求时创建一个新上下文来解决问题。这在技术上解决了我的问题,但我想知道是否有办法在保持相同的背景下这样做。

那么,有没有人有这方面的经验?我发现很难相信我是第一个遇到这个问题的人,但我在这里找到的类似问题的所有其他答案都建议我使用CancellationToken(这不能正常工作)或有点旧,不适用于Async方法。

编辑1:

由于还没有人回答这个问题,我真的开始想知道我的选择是什么。一点背景。我正在将Silverlight应用程序转换为WPF。Silverlight应用程序在EF 4.1中使用WCF RIA服务,但是对于WPF应用程序,我们决定只使用EF6.1。

使用Silverlight& WCF,你可以在时间上做的异步调用的数量没有限制,我们实际上有一个整个应用程序的上下文(糟糕,我知道,但很简单,我们从来没有遇到任何问题)。我们只是直接绑定到实体,并使用更改跟踪来保存用户所做的更改。

在真实世界的应用程序中,使用EF 6.1和Async方法无法在WPF中执行此操作,有时,您只需要取消应用程序在执行过程中所执行的操作做什么用户想要的,而不会崩溃和燃烧?

1 个答案:

答案 0 :(得分:0)

暂时发布我的解决方案。我并不是一个忠实的粉丝,但我能够开始工作并不需要从头开始重写这个应用程序。

我现在在访问或保存跟踪实体的存储库方法中使用AsyncEx中的AsyncLock类。每个DbContext对象都使用自己的锁,因此我不会阻止来自其他上下文或未跟踪实体的其他调用。

例如,我的存储库中的GetListAsync方法:

public async virtual Task<IList<T>> GetListAsync(IDbContext context,
                                                 Expression<Func<T, bool>> where,
                                                 IOrderByClause<T>[] orderBy = null,
                                                 params Expression<Func<T, object>>[] navigationProperties)
{
    using (await context.ContextLock.LockAsync())
    {
        IList<T> list = await GetListQuery(context, where, orderBy, navigationProperties).ToListAsync();
        return list;
    }
}

GetListQuery使用nav属性以及where和order by子句创建查询。

我也可能使用CancellationToken添加超时。