views:

67

answers:

3

Hi,

I'm new with EntityFramework.

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

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.

Example:

Let's imagine a table called tbl.

The table has 2 columns: id and data.

There is 1 row: id = 1, data = 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.

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!

+1  A: 

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.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.

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.

So basically, don't do it :)

Andras Zoltan
But creating a context creates new DB connection and it takes time.Where is my mistake?
Mattan
Read the articles I've linked to and trust them! You don't need to worry about connection management - all the pooling etc is taken care for you. Open the context, do some record accessing/creation etc, close the context.
Andras Zoltan
+2  A: 

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

James
But creating a context creates new DB connection and it takes time. Where is my mistake?
Mattan
@Mattan, yes it does, but it is better to open a connection do some work and close the connection than having a connection open for long periods of time.
James
@Mattan, @James, creating an ObjectContext does *not* create a new DB connection. It grabs one from a pool. @Mattan is prematurely optimizing. +1 for James and @Andras; this is a bad design and needs to be changed.
Craig Stuntz
I read the articles and changed my application (As I told, I'm new with entity framework).I checked the time spent for the create and dispose of the context, and its not so small... I don't think that I can afford it now.Other solution I have found is to set MergeOption.OverwriteChanges.
Mattan
@Mattan, let it go; *you are wrong*. Instantiating and disposing an `ObjectContext` is not an expensive operation, and *does not* directly cause a DB connection. You are [prematurely optimizing](http://c2.com/cgi/wiki?PrematureOptimization), which is the cause of your incorrect design. By keeping this bad design going, you are only compounding your initial mistake.
Craig Stuntz
+1 @Craig, the overall design is wrong. Object contexts weren't designed to be kept alive for long and you have mentioned your application is multi-threaded....object contexts *aren't* thread safe.
James
Hi,About the thread-safety issue: I know about it and because of it I'm using a pool of contexts so only 1 thread can access each context at a time.Craig: I think you right, and I've changed my application according to your explaination, but for now, I can see that the performances are ~15% lower...I have a server with more then 100 requests per second, so I'm not sure I can afford it...
Mattan
@Mattan, you need to profile your app and fix the slow parts, not make wild guesses at what is slow. Your performance issues much more likely coming from poor memory management due to long-lived instances than they are from very lightweight `new` statements. If your DB connects are too slow, the issue is DB driver connection pooling, not `ObjectContext` instantiation.
Craig Stuntz
Andras Zoltan
As I said, I changed my design according to your advices.I just asked more questions...Anyway thanks a lot!
Mattan
@Mattan - okay - sorry if I got a little heated there. I agree with @Craig Stuntz here about the performance. Although I can see why you went that way initially with the design, it's definitely best that you have now changed it. With regards to the performance there will be other places you can get the performance back outside of the objectcontext - I use it here for high-traffic apps with no concerns.
Andras Zoltan
A: 

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:

  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 EntityConnection to 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.

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

Craig Stuntz