简体   繁体   English

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

[英]Cancel Long Running Entity Framework 6 async requests

I'm using Entity Framework 6 ( DbContext ) in a WPF application, and I'd like to find a way to properly cancel the async data load methods ( ToListAsync & FirstOrDefaultAsync ) so I can immediately start another request. 我在WPF应用程序中使用Entity Framework 6( DbContext ),我想找到一种方法来正确取消async数据加载方法( ToListAsyncFirstOrDefaultAsync ),这样我就可以立即启动另一个请求。

I've been trying to stick with the single context per form (tab in my case) standard, and so far, I've been dealing with the non-thread safe nature of these calls by ensuring that the UI is disabled during requests, so the user can't start any new requests while one's in progress. 我一直在努力坚持每个表单的单个上下文(在我的情况下是tab)标准,到目前为止,我一直在通过确保在请求期间禁用UI来处理这些调用的非线程安全性质,因此,当用户正在进行时,用户无法启动任何新请求。 However, I've run into a use case now where this is just not possible. 但是,我现在遇到一个用例,这是不可能的。 I need to keep the UI responsive during some long-running requests, and in order to do that, I need a way to cancel the current request and start another one right away. 我需要在一些长时间运行的请求期间保持UI响应,为了做到这一点,我需要一种方法来取消当前请求并立即启动另一个请求。

I've tried leveraging the CancellationToken support that was added to the Async methods, but I've found that when I cancel the request, it doesn't actually cancel anything. 我已经尝试利用添加到Async方法的CancellationToken支持,但我发现当我取消请求时,它实际上并没有取消任何内容。 It will properly throw the OperationCanceledException , but the request is still in progress, and when I try to make another request after that, I still get NotSupportedException (A second operation started on this context...) 它将正确抛出OperationCanceledException ,但请求仍在进行中,当我尝试在此之后再发出请求时,我仍然得到NotSupportedException (A second operation started on this context...)

I'm using change-tracking, so changing the app to use a new Context for every request is not realistic. 我正在使用更改跟踪,因此更改应用程序以为每个请求使用新的上下文是不现实的。

Also, I've temporarily gotten around the issue by disposing the current context and creating a new one every time this particular view model makes a request while one's already in progress. 此外,我暂时解决了这个问题,处理当前上下文并在每次特定视图模型发出请求时创建一个新上下文,而其中一个已在进行中。 This technically solves my issue, but I'm wondering if there's a way to do it while staying with the same context. 这在技术上解决了我的问题,但我想知道是否有办法在保持相同的背景下这样做。

So, does anyone have any experience with this? 那么,有没有人有这方面的经验? I find it hard to believe I'm the first one who's run into this issue, but all other answers I've found on here for similar questions either recommend I use the CancellationToken (which doesn't work properly) or are a bit older and don't apply to the Async methods. 我发现很难相信我是第一个遇到这个问题的人,但是我在这里找到的类似问题的所有其他答案要么建议我使用CancellationToken (这不能正常工作),要么是有点旧并且不适用于Async方法。

EDIT 1: 编辑1:

Since no one's answered this yet, I'm really starting to wonder what my options are here. 既然没有人回答这个问题,我真的开始想知道我的选择是什么。 A bit of background. 一点背景。 I'm converting a Silverlight application to WPF.The Silverlight application was using WCF RIA services with EF 4.1, but with the WPF application, we decided to just use EF6.1. 我正在将Silverlight应用程序转换为WPF。Silverlight应用程序在EF 4.1中使用WCF RIA服务,但是对于WPF应用程序,我们决定只使用EF6.1。

With Silverlight & WCF, there is no limit to the number of async calls you can make at time, and we actually have a single context for the entire application (bad, I know, but simple and we never had any issues). 使用Silverlight和WCF,您可以随时进行异步调用的数量没有限制,我们实际上只有整个应用程序的单个上下文(糟糕,我知道,但很简单,我们从来没有遇到任何问题)。 We just bind directly to the entities, and use change-tracking to save the changes made by the user. 我们只是直接绑定到实体,并使用更改跟踪来保存用户所做的更改。

Is there just no way to do this in WPF, using EF 6.1 and the Async methods, in a real world application, where sometimes, you just need to cancel what the app is in the progress of doing and do what the user wants, without crashing and burning? 在真实世界的应用程序中,使用EF 6.1和Async方法在WPF中无法做到这一点,有时,您只需要取消应用程序在执行过程中所执行的操作并执行用户想要的操作,崩溃和燃烧?

Posting my solution for now. 暂时发布我的解决方案。 I'm not a huge fan, but it's all I've been able to get to work that wouldn't require completely rewriting this application from scratch. 我不是一个狂热的粉丝,但是我已经能够开始工作,不需要从头开始重写这个应用程序。

I'm now using the AsyncLock class from AsyncEx in repository methods that are accessing or saving tracked entities. 现在我使用的AsyncLock从类AsyncEx中正在访问或保存跟踪实体库的方法。 Each of the DbContext objects use their own lock, so I'm not blocking other calls from other contexts or for untracked entities. 每个DbContext对象都使用自己的锁,因此我不会阻止来自其他上下文或未跟踪实体的其他调用。

As an example, my GetListAsync method in my repository: 作为示例,我的存储库中的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 creates the query using the nav properties and where and order by clauses. GetListQuery使用nav属性以及where和order by子句创建查询。

I'll probably also add a timeout as well, using a CancellationToken. 我也可能使用CancellationToken添加超时。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM