oracle 实体框架:如何使用多个上下文并保持同步?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3289765/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-18 21:04:29  来源:igfitidea点击:

Entity framework: How can I use more then one context and stay synchronized?

c#databasevisual-studiooracleentity-framework

提问by Mattan

I'm new with EntityFramework.

我是 EntityFramework 的新手。

My application has a pool of context object instances (Each context has 1 connection to the DB).

我的应用程序有一个上下文对象实例池(每个上下文有 1 个到数据库的连接)。

The problem is that when I update an object (and calling SaveChanges), the data is updated in the DB and in the updating context but when I select from other instance, it gets the old data of the selected object.

问题是,当我更新一个对象(并调用 SaveChanges)时,数据会在数据库和更新上下文中更新,但是当我从其他实例中选择时,它会获取所选对象的旧数据。

Example:

例子:

Let's imagine a table called tbl.

让我们想象一个名为 tbl 的表。

The table has 2 columns: id and data.

该表有 2 列:id 和 data。

There is 1 row: id = 1, data = 2.

有 1 行:id = 1,数据 = 2。

EFContext context1 = new EFContext();      
EFContext context2 = new EFContext();      
var obj1 = context1.tbl.Where(a => a.id == 1);      
var obj2 = context2.tbl.Where(a => a.id == 1);      
obj2.data = 10;      
context2.SaveChanges(); 
var obj3 = context1.tbl.Where(a => a.id == 1); 

After executing these lines, obj3.data contains 2, instead of 10.

执行这些行后,obj3.data 包含 2,而不是 10。

How can I solve this problem?

我怎么解决这个问题?

I don't want to create a context instance every time I want to access the DB.

我不想每次访问数据库时都创建上下文实例。

Refresh is not good enough I'll have to do it before every query (My application is multithreaded), and it takes a lot of time.

刷新不够好,我必须在每次查询之前都这样做(我的应用程序是多线程的),而且需要很多时间。

If I had a way to tell entity framework to perform a query every time I'm trying to select, it would be great.

如果我有办法告诉实体框架在我每次尝试选择时执行查询,那就太好了。

Thanks!

谢谢!

回答by James

You need to rethink your design. Contexts are very lightweight and it is usually standard practice to create one per transaction or unit of work. A good rule of thumb I go by when dealing with database interactions is open connections as late as possible and close them as soon as possible, in your case you are leaving mutliple database connections open unnecessarily.

你需要重新考虑你的设计。上下文非常轻量级,通常为每个事务或工作单元创建一个上下文是标准做法。我在处理数据库交互时遵循的一个很好的经验法则是尽可能晚地打开连接并尽快关闭它们,在您的情况下,您不必要地打开多个数据库连接。

You should consider applying a better design pattern to your problem, have a look at the Repository and Unit of Work pattern

您应该考虑将更好的设计模式应用于您的问题,查看存储库和工作单元模式

回答by Andras Zoltan

You're not meant to be holding a reference to object contexts over a long period of time.

您不打算在很长一段时间内持有对对象上下文的引用。

http://blogs.microsoft.co.il/blogs/gilf/archive/2010/02/07/entity-framework-context-lifetime-best-practices.aspx

http://blogs.microsoft.co.il/blogs/gilf/archive/2010/02/07/entity-framework-context-lifetime-best-practices.aspx

http://blogs.msdn.com/b/alexj/archive/2009/05/07/tip-18-how-to-decide-on-a-lifetime-for-your-objectcontext.aspx

http://blogs.msdn.com/b/alexj/archive/2009/05/07/tip-18-how-to-decide-on-a-lifetime-for-your-objectcontext.aspx

This second one also points out:

第二个也指出:

Thread Safety: If you are trying to re-use an ObjectContext you should be aware that is not thread safe, i.e. similar to the standard .NET collection classes. If you access it from many threads (e.g. web requests) you will need to insure that you synchronize access manually.

线程安全:如果您尝试重用 ObjectContext,您应该意识到它不是线程安全的,即类似于标准的 .NET 集合类。如果您从多个线程(例如 Web 请求)访问它,您将需要确保手动同步访问。

So, basically, you're going to have to lock over the whole context. Instead you can simply use an instance for each thread (created as per the best practises described) and let the database handle the concurrency issues. Even better, use transactions.

所以,基本上,你将不得不锁定整个上下文。相反,您可以简单地为每个线程使用一个实例(根据所描述的最佳实践创建)并让数据库处理并发问题。更好的是,使用交易

Although it is tempting to try and keep a context open for a long period of time to save on creation/disposal etc - in practise you should be opening and closing a context as and when you need it.

尽管尝试将上下文保持打开很长时间以节省创建/处置等很诱人,但实际上您应该在需要时打开和关闭上下文。

This is made easier with EF due to the fact that you can take an object from a context and reattach it to another later - something that is difficult, if not impossible to do with Linq to SQL.

使用 EF 更容易,因为您可以从上下文中获取一个对象,然后将其重新附加到另一个对象 - 这对于 Linq to SQL 来说是困难的,如果不是不可能的话。

So basically, don't do it :)

所以基本上,不要这样做:)

回答by Craig Stuntz

Note that it is possible to hold DB connections open across multiple OC lifetimes, even if your provider won't pool them. A couple things you can adjust after profiling:

请注意,即使您的提供者不会将它们池化,也可以在多个 OC 生命周期内保持数据库连接打开。您可以在分析后调整以下几点:

  1. Explicitly opening the Context.Connection when you instantiate the OC. Prevents the context from requesting a new connection for each query.

  2. Provide an existing EntityConnectionto the constructor of the OC. Then it will use the existing connection across multiple OC lifetimes.

  3. Precompile EF queries; they're cached in the OC. Precompiling them allows the cache to span multiple OC instances.

  1. 在实例化 OC 时显式打开 Context.Connection。防止上下文为每个查询请求新连接。

  2. EntityConnectionOC 的构造函数提供一个存在。然后它将跨多个 OC 生命周期使用现有连接。

  3. 预编译 EF 查询;它们缓存在 OC 中。预编译它们允许缓存跨越多个 OC 实例。

Again, the OC constructor is notexpensive. You mustfirst profile and find the slow part. Fix that, not the OC; it isn't broken.

同样,OC 构造函数并不昂贵。您必须首先分析并找到缓慢的部分。解决这个问题,而不是 OC;它没有坏。

回答by yubaolee

as @Andras Zoltan say: You're not meant to be holding a reference to object contexts over a long period of time.

正如@Andras Zoltan 所说:您不应该长期持有对对象上下文的引用。

EFContext context1 = new EFContext();      
EFContext context2 = new EFContext();      
var obj1 = context1.tbl.Where(a => a.id == 1);      
var obj2 = context2.tbl.Where(a => a.id == 1);      
obj2.data = 10;      
context2.SaveChanges(); 
EFContext context3 = new EFContext();   //new context
var obj3 = context3.tbl.Where(a => a.id == 1);