线程安全的实体框架 6 [英] Thread safe Entity Framework 6

查看:15
本文介绍了线程安全的实体框架 6的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

刚刚开始测试 EF6 及其异步功能.当我意识到它们不是线程安全的时,我很惊讶.我有点假设这就是重点.

Just starting testing EF6 and its Async functions. Boy was I surprised when I realized that they are not thread safe. I kinda assumed that that was the point.

多年来,我已经拥有自己的基于 Task 的扩展方法,但我一直在等待 EF 让它们成为线程安全的.

I had my own Task based extension methods for years already, but what I was waiting for from EF was to make them thread safe.

至少我的基于任务的功能 locked 不会相互干扰.EF6 甚至没有走那么远.但主要问题是我的代码与他们的代码共享.即尝试发出异步查询,然后在它完成之前尝试访问触发延迟加载的导航属性(在同一上下文中预加载的完全独立的实体上).这可以由 UI 触发,也可以由即时函数之外的其他代码触发,也可以由许多其他场景触发.

At least my Task based functions locked as to not interfere with each other. EF6 doesn't even go that far. But the main problem is something that my code shares with theirs. i.e. Try issuing an async query and then before it completes try accessing a navigation property (on a pre-loaded totally separate entity in the same context) which triggers lazy loading. This could be triggered either by the UI, or by other code outside of the immediate function, or by a dozen other scenarios.

据我所知.dbContext 中仅有的两个共享(实体之间)可变资源是连接和更改跟踪(缓存).如果我们可以在这些功能周围添加锁定,那么我们将拥有一个线程安全的上下文.

As far as I can tell. The only two shared (between entities) mutable resources in a dbContext are the connection and change tracking (caching). If we could add locking around those to functionalities then we would have a thread safe context.

我们甚至可以分两个阶段完成.如果我们可以实现一个提供者来锁定用于查询数据库的一个集中功能.然后任何未跟踪的查询 - 通过返回非实体(匿名)对象或通过调用 AsNoTracking() - 将是线程安全的,并且即使在另一个线程可能要求延迟加载的对象时也可以安全地使用 Async 函数调用.

We could even do it in two stages. If we could implement a provider that locked the one centralized function used to query the database. Then any non tracked queries - either by returning non entity (anonymous) objects or by calling AsNoTracking() - would be thread safe, and would be safe to call with Async functions even when another thread might be asking for a lazy loaded object.

我们的可扩展性不会比现在更糟,因为我们现在必须为每个线程使用一个上下文,如果您尝试跳过甚至一个 await 以引入一些并行性或正在工作,即使是 Async 函数也不适用在事件系统(如 wpf)中,一旦等待的函数与任务一起返回,可能会触发.

Our scaleability would be no worse off then we are now that we have to use one context per thread, and even the Async functions are off the table if you try to skip even one await to introduce a bit of parallelism or are working in an evented system (like wpf) that might trigger once the awaited function returns with the task.

所以我的问题是.有没有人实现过这样的提供者.或者有人愿意和我一起工作吗?

So my question is. Has anyone implemented a provider like this. Or would anyone be willing to work with me on it?

推荐答案

我认为您正面临架构问题.您描述的是一个 UI 直接使用 EF 对象的应用程序,它打破了关注点分离"范式.

I think you are facing an architectural issue. What you describes is an application where UI directly uses EF objects, and it breaks the "separation of concerns" paradigm.

在我这边,我在模型层上使用自定义线程安全缓存,让一切都发生在模型层上.我使用众所周知的 AsyncLock 在我的缓存上实现了线程安全.

On my side, I use customs thread-safe caches on a Model layer, letting everything happens on the Model layer. I implemented thread-safety on my cache with the well-known AsyncLock.

DbContext 对象,并且每个 EF CRUD 相关操作都有一个非常有限的生命周期.每个 CRUD 操作实例化它自己的 DbContext,并将模型对象返回到缓存,然后,上下文被垃圾收集.我的应用程序使用缓存作为抽象层,而缓存使用 EF 作为 DB 抽象层.

DbContext objects, and every EF CRUD related operations have a very limited lifetime. Each CRUD Operation instantiate it's own DbContext, and returns Model Objects to the cache, then, contexts are garbage collected. My applications uses caches as an abstraction layer, and caches uses EF as a DB abstraction layer.

例如,探索对象上的附加属性,是通过在模型层上实现自定义方法来完成的,该方法以对象 ID 作为参数,并将相关对象的列表返回到缓存中.UI 询问 Cache,然后 Cache 询问 EF,一旦可用,对缓存的调用会将对象返回给 UI.就这么简单.

For example, exploring attached properties on Objects, is done by implementing custom methods on the Model layer, which takes the object Id as parameter, and returns a list of related objects to the cache. The UI asks the Cache, then the Cache asks EF, then once available, the call made to the cache returns objects to the UI. Simple as that.

EntityFramework 并非设计为线程安全的,因此无法以多线程方式使用它.(EF 线程安全)

EntityFramework is not designed to be thread safe, so there's no way to work with it in a multi-threaded way. (EF thread safety)

您必须构建一个可以以多线程方式访问的模型层,而不是并行访问您的 DbContext.您的模型可以对您的 DB 进行多次并行调用,但请记住,每个调用都必须实例化并保持其自己的 DbContext.在每次调用结束时,必须释放相关的 DbContext.

Instead of having parallel access to you DbContext, you have to build a Model layer which can be accessed in a multi-threaded way. And your model can make multiple parallel calls to you DB, but keep in mind that each call must instantiate and keep it's own DbContext. At the end of each call, the related DbContext must be disposed.

DbContext 实例化速度非常快,唯一的缺点是网络延迟.这就是为什么内存缓存是个好主意.

DbContext are really fast to instantiate, the only downside is the network latency. That's why a memory cache is a good idea.

这篇关于线程安全的实体框架 6的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆