Entity Framework DbContext and thread safety - c#

I need to update a few tables in my DB in a single transaction and I read that using DbContext.SaveChanges should be the way to do so.
However I also read that the lifetime of the DbContext should be as short as possible because it grows over time as it loads more entities.
Also I read that in order to make it thread-safe, each action should have its own DbContext.
Should I have a DbContext for each table I want to change and call SaveChanges on each DbContext? Wouldn't the last SaveChanges call override the changes of the previous calls?
What is the best way to do it? (I need this for a website)

Entity Framework is not thread-safe. An MVC controller is instantiated per request. Thus if you use one DbContext per request, you're safe as long as you don't manually spawn threads in your controller actions (which you shouldn't do anyway).
Now if you have concurrency in your application, like a reservation system where multiple users are out to access the same scarce resources that can run out (like tickets), you'll have to implement logic around that yourself. No thread safety is going to help you there anyway.
That's why you're being asked for code in comments, because explaining thread safety in general is way too broad, and probably not applicable to your situation.

Simple way is, to have one DbContext per request, ASP.NET MVC does all thread safety, each controller instance in ASP.NET MVC is isolated for every request, you don't have to worry about race conditions. As long as you don't create threads and just simply do data transformation in action method using single DbContext, you will not have any problem.
Basically DbContext does nothing, it just queues SQL query to target database, it is the database which handles multi threading, race conditions. To protect your data, you should use transactions and add validations in your database to make sure they are saved correctly
public abstract class DbContextController : Controller{
public AppDbContext DB { get; private set;}
public DbContextController(){
DB = new AppDbContext();
}
protected override void OnDisposing(bool disposing){
DB.Dispose();
}
}
If you inherit any class from DbContextController and use DB throughout the life of controller, you will not have any problem.
public ActionResult ProcessProducts(){
foreach(var p in DB.Products){
p.Processed = true;
foreach(var order in p.Orders){
order.Processed = true;
}
}
DB.SaveChanges();
}
However, if you use any threads like in following example,
public ActionResult ProcessProducts(){
Parallel.ForEach(DB.Products, p=>{
p.Processed = true;
// this fails, as p.Orders query is fired
// from same DbContext in multiple threads
foreach(var order in p.Orders){
order.Processed = true;
}
});
DB.SaveChanges();
}

Related

ASP.NET MVC with EF and the Dispose Pattern

I'm writing an ASP.NET MVC application with EF. I have some questions regarding whether or not my approach is reasonable. Note: I simplified my basic structure for this question, in realitiy everything is coupled more loosely.
Let's assume a View that allows a user to change properties of a complex domain model. The data originates from the Database (via EF) and has to be written back again in the end.
From my understanding, each request results in a new controller instance being called. Therefore, I'm using the 'Dispose Pattern' described here as Option 2, which ensures a new DbContext for every request:
public class MyController : Controller
{
private MyContext repo = new MyContext();
protected override void Dispose(bool disposing)
{
this.repo.Dispose();
base.Dispose(disposing);
}
//more code...
}
Now there is a public ActionResult Edit(elementId) method on the controller that will fetch an element from the database and displays an editor for it. Once this request is finished, any reference to the Dbcontext is gone, but I still have access to the Entity-Object fetched from the DB as I store it in my session.
Later on the user presses a 'Save' button on the View. The request to the Save-method of my Controller once again creates a new instance of the Controller and therefore a new DbContext. The Entity-object stored in my session is retrieved and its properties are modified according to the user's input. To save the new state to the database, I have to attach it to the new context:
public void Save()
{
this.repo.MyTable.Attach(myEntity);
myEntity.Name = "New Name";
this.repo.SaveChanges();
}
This can only work once the old Controller with the original DbContext of myEntity has been disposed, otherwise 'Attach' would fail (unable to attach Entity to two contexts). I'm concerned whether or not I can rely on the old DbContext being disposed here.
Also: I know that using an IoC framework would be an alternative. How would that apply to my situation, what would be the benefits?
I think you've redacted too much of your code in an effort to "simplify" the question, and as a result, have actually obscured some important issues. However, based on the Save method you've posted, I can pretty well guess your issue. Your repo is most likely creating it's own context, which is a pretty big no-no.
To answer you overall question, the rationale for implementing IDisposable here is the same as anywhere else: any class that owns dependencies that implement IDisposable should also implement IDisposable. Here, your controller instantiates MyContext, so it should therefore dispose of MyContext when its done. Simple as that.
However, if you introduce dependency injection, and inject the context into the controller, then the controller no longer owns the context. Instead, the DI container will own it. Therefore, your controller should not dispose of the context, as it does not own it.
And, you should use dependency injection here. Your context should be injected into your repository and then your repository should be injected into your controller. This ensures that there's is only one context instance, and you won't have issues like you're experiencing now, where EF complains that the entity belongs to a different context.
Finally, I just want to parrot #SteveGreene in saying that there is absolutely no reason to store your entity in the session, and in fact there's many reasons you shouldn't, not the least of which being it will frustrate any efforts to move away from In Proc sessions to a more reliable session store. Once you're using something like StateServer, SQL Server, Redis, etc., anything you put in the session must be serializable, and entities are often quite difficult if not impossible to serialize, since they often have many relationships with other entities and often circular relationships with those entities.

UnitOfWork struggling with multiple simultaneous connections

Apparently (and quite possibly) there's a flaw in my current UnitOfWork implementation, because I have connection errors when doing many calls at once.
Exception:
The underlying provider failed on Open.
Inner Exception:
The connection was not closed. The connection's current state is
connecting.
This results in a HTTP 500 response on the client side.
UnitOfWork implementation
public class ScopedUnitOfWork : IUnitOfWork
{
public Entities Context { get; set; }
public UnitOfWorkState State { get; set; }
public ScopedUnitOfWork(IEnvironmentInformationProvider environmentInformationProvider)
{
this.Context = new Entities(environmentInformationProvider.ConnectionString);
this.State = UnitOfWorkState.Initialized;
}
public UowScope GetScope()
{
this.State = UnitOfWorkState.Working;
return new UowScope(this);
}
public SaveResult Save()
{
if (this.State != UnitOfWorkState.Working)
throw new InvalidOperationException("Not allowed to save out of Scope. Request an UowScope instance by calling method GetScope().");
this.Context.SaveChanges();
this.State = UnitOfWorkState.Finished;
return new SaveResult(ResultCodes.Ok);
}
}
Working on a single UowScope would solve the issue but that's not possible given the current circumstance, because each request is completely separate. De facto each request IS using an UoWScope, but apparently it goes wrong when the UoW receives many calls at once.
The UoW is injected through Unity IoC, so I suppose it's a singleton in effect.
The question
Is there a way to adapt the UoW so that separate high-frequency requests are not an issue?
Preferably I'd solve this server side, not client side, any tips? Thanks!
Disclaimer
I don't claim I fully understand UoW, so my implementation may need improvement, be gentle :). Any improvements on that are certainly welcome!
UPDATE
I -know- the EF Context is an UoW, I use mine at Domain level to enable transactional processing of data that is functionality related. And it's also by customer demand, I have no choice.
The issue you have is that the unit of work object is effectively a singleton as your IoC framework is keeping it around for the duration of your application. This means that your context is also being kept as a singleton as it's inside the UoW. So you will almost certainly get multiple concurrent calls to your context which will throw exceptions.
However, I think you are misusing the concept of what a UoW supposed to do. A UoW is there to provide a container for a group of transactions. For example lets say you have an eCommerce platform. When you create an order, you will insert a row in the orders table, then as part of the same transaction you will also insert rows into the order items table, update a users loyalty points etc. So you should do all this inside a single unit of work, commit it, then destroy it. Let the IoC framework (Unity in this case) create your unit of work for each session.

Entity Framework - concurrent use of containers

In the Business Logic Layer of an Entity Framework-based application, all methods acting on DB should (as I've heard) be included within:
using(FunkyContainer fc = new FunkyContainer())
{
// do the thing
fc.SaveChanges();
}
Of course, for my own convenience often times those methods use each other, for the sake of not repeating myself. The risk I see here is the following:
public void MainMethod()
{
using(FunkyContainer fc = new FunkyContainer())
{
// perform some operations on fc
// modify a few objects downloaded from DB
int x = HelperMethod();
// act on fc again
fc.SaveChanges();
}
}
public int HelperMethod()
{
using(FunkyContainer fc2 = new FunkyContainer())
{
// act on fc2 an then:
fc2.SaveChanges();
return 42;
}
}
I doesn't look good to me, when the container fc2 is created, while fc is still open and has not been saved yet. So this leads to my question number one:
Is having multiple containers open at the same time and acting on them carelessly an acceptable practice?
I came to a conclusion, that I could write a simple guard-styled object like this:
public sealed class FunkyContainerAccessGuard : IDisposable
{
private static FunkyContainer GlobalContainer { get; private set; }
public FunkyContainer Container // simply a non-static adapter for syntactic convenience
{
get
{
return GlobalContainer;
}
}
private bool IsRootOfHierarchy { get; set; }
public FunkyContainerAccessGuard()
{
IsRootOfHierarchy = (GlobalContainer == null);
if (IsRootOfHierarchy)
GlobalContainer = new FunkyContainer();
}
public void Dispose()
{
if (IsRootOfHierarchy)
{
GlobalContainer.Dispose();
GlobalContainer = null;
}
}
}
Now the usage would be as following:
public void MainMethod()
{
using(FunkyContainerAccessGuard guard = new FunkyContainerAccessGuard())
{
FunkyContainer fc = guard.Container;
// do anything with fc
int x = HelperMethod();
fc.SaveChanges();
}
}
public int HelperMethod()
{
using(FunkyContainerAccessGuard guard = new FunkyContainerAccessGuard())
{
FunkyContainer fc2 = guard.Container;
// do anything with fc2
fc2.SaveChanges();
}
}
When the HelperMethod is called by MainMethod, the GlobalContainer is already created, and its used by both methods, so there is no conflict. Moreover, HelperMethod can be also used separately, and then it creates its own container.
However, this seems like a massive overkill to me; so:
Has this problem been already solved in form of some class (IoC?) or at least some nice design pattern?
Thank you.
Is having multiple containers open at the same time and acting on them carelessly an acceptable practice?
Generally this is perfectly acceptable, sometimes even necessary, but you have to be caucious with that. To have multiple containers at the same time is especially handy when doing multithreading operations. Because of how db works generally each thread should have its own DbContext that should not be shared with other threads. Downside to using multiple DbContext at the same time is that each of them will use separate db connection, and sometimes they are limited, what may lead to application occasionally being unable to connect to database. Other downside is the fact that entity generated by one DbContext may not be used with entity generated by other DbContext. In your example HelperMethod returns primitive type, so this is perfectly safe, but if it would return some entity object that in MainMethod you would like to assign for instance to some navigation property of entity created by MainMethod DbContext then you will receive an exception. To overcome this in MainMethod you would have to use Id of entity returned by HelperMethod to retrieve that entity once more, this time with fc context. On the other hand there is an advantage of using multiple contexts - if one context have some troubles, for instance it tried to save something that violated index constaint, then all next trials of saving changes will result in the same exception as the faulty change will still be pending. If you use multiple DbContexts then if one would fail, then second will operate independently - this is why DbContexts should not live long. So generally I would say the best usage rule would be:
Each thread should use a separate DbContext
All methods that executes on the same thread should share the same DbContext
Of course the above applies if the job to be done is short. DbContext should not live long. The best example would be web applications - there each server request is handled by separate thread and the operations to generate response generally do not take long. In such case all methods executed to generate one response should share for convenience the same DbContext. But each request should be served by separate DbContext.
Has this problem been already solved in form of some class (IoC?) or at least some nice design pattern?
What you need to assure is that your DbContext class is singleton per thread, but each thread has its own instance of that class. In my opinion best way to assure this is with IoC. For instance in Autofac in web applications I register my DbContext with the following rule:
builder
.RegisterType<MyDbContext>()
.InstancePerHttpRequest();
This way autofac IoC generates one DbContext per request and share existing instance within the request serving thread. You do not need to care here for disposing your DbContext. Your IoC will do this when your thread is over.
Working in multiple connections at the same time is not the right approach most of the time because:
You can get distributed deadlocks that SQL Server cannot resolve.
You might not see data that was previously written but not yet committed.
You can't share entities across context boundaries (here: methods).
More resource usage.
No ability to transact across context boundaries (here: methods).
These are very severe disadvantages. Usually, the best model is to have one context, connection and transaction for the request that the app is processing (HTTP or WCF request). That's very simple to set up and avoids a lot of issues.
EF is supposed to be used as a live object model. Do not cripple it by reducing it to CRUD.
static FunkyContainer GlobalContainer
That does not work. You shouldn't share a context across requests. Super dangerous. Consider storing a context in HttpContext.Items or whatever is the per-request store in your app.

Using DbContext SaveChanges with Transactions

As MSDN confirms, in EF 5 and on, the DbContext class is "a combination of the Unit-Of-Work and Repository patterns." In the web applications I build, I tend to implement the Repository and Unit-Of-Work patterns on top of the existing DbContext class. Lately, like many others out there, I've found that this is overkill in my scenario. I am not worried about the underlying storage mechanism ever changing from SQL Server, and while I appreciate the benefits that unit testing would bring, I still have a lot to learn about it before actually implementing it in a live application.
Thus, my solution is to use the DbContext class directly as the Repository and Unit-Of-Work, and then use StructureMap to inject one instance per request to individual service classes, allowing them to do work on the context. Then in my controllers, I inject each service I need and call the methods necessary by each action accordingly. Also, each request is wrapped in a transaction created off of the DbContext at the beginning of the request and either rolled back if any type of exception occurred (whether it be an EF error or application error) or committed if all is well. A sample code scenario is below.
This sample uses the Territory and Shipper tables from the Northwind sample database. In this sample admin controller, a territory and a shipper are being added at the same time.
Controller
public class AdminController : Controller
{
private readonly TerritoryService _territoryService;
private readonly ShipperService _shipperService;
public AdminController(TerritoryService territoryService, ShipperService shipperService)
{
_territoryService = territoryService;
_shipperService = shipperService;
}
// all other actions omitted...
[HttpPost]
public ActionResult Insert(AdminInsertViewModel viewModel)
{
if (!ModelState.IsValid)
return View(viewModel);
var newTerritory = // omitted code to map from viewModel
var newShipper = // omitted code to map from viewModel
_territoryService.Insert(newTerritory);
_shipperService.Insert(newShipper);
return RedirectToAction("SomeAction");
}
}
Territory Service
public class TerritoryService
{
private readonly NorthwindDbContext _dbContext;
public TerritoryService(NorthwindDbContext dbContext)
{
_dbContext = dbContext;
}
public void Insert(Territory territory)
{
_dbContext.Territories.Add(territory);
}
}
Shipper Service
public class ShipperService
{
private readonly NorthwindDbContext _dbContext;
public ShipperService(NorthwindDbContext dbContext)
{
_dbContext = dbContext;
}
public void Insert(Shipper shipper)
{
_dbContext.Shippers.Add(shipper);
}
}
Creation of Transaction on Application_BeginRequest()
// _dbContext is an injected instance per request just like in services
HttpContext.Items["_Transaction"] = _dbContext.Database.BeginTransaction(System.Data.IsolationLevel.ReadCommitted);
Rollback or Commit of Transaction on Application_EndRequest
var transaction = (DbContextTransaction)HttpContext.Items["_Transaction"];
if (HttpContext.Items["_Error"] != null) // populated on Application_Error() in global
{
transaction.Rollback();
}
else
{
transaction.Commit();
}
Now this all seems to work well, but the only question I have now is where is it best to call the SaveChanges() function on the DbContext? Should I call it in each Service layer method?
public class TerritoryService
{
// omitted code minus changes to Insert() method below
public void Insert(Territory territory)
{
_dbContext.Territories.Add(territory);
_dbContext.SaveChanges(); // <== Call it here?
}
}
public class ShipperService
{
// omitted code minus changes to Insert() method below
public void Insert(Shipper shipper)
{
_dbContext.Shippers.Add(shipper);
_dbContext.SaveChanges(); // <== Call it here?
}
}
Or should I leave the service class Insert() methods as is and just call SaveChanges() right before the transaction is committed?
var transaction = (DbContextTransaction)HttpContext.Items["_Transaction"];
// HttpContext.Items["_Error"] populated on Application_Error() in global
if (HttpContext.Items["_Error"] != null)
{
transaction.Rollback();
}
else
{
// _dbContext is an injected instance per request just like in services
_dbContext.SaveChanges(); // <== Call it here?
transaction.Commit();
}
Is either way okay? Is it safe to call SaveChanges() more than once since it is wrapped in a transaction? Are there any issues I may run into by doing so? Or is it best to call SaveChanges() just once right before the transaction is actually committed? I personally would rather just call it at the end right before the transaction is committed, but I want to be sure I am not missing any gotcha's with transactions or doing something wrong? If you read this far, thanks for taking the time to help. I know this was a long question.
You would call SaveChanges() when it's time to commit a single, atomic persistence operation. Since your services don't really know about each other or depend on each other, internally they have no way to guarantee one or the other is going to commit the changes. So in this setup I imagine they would each have to commit their changes.
This of course leads to the problem that these operations might not be individually atomic. Consider this scenario:
_territoryService.Insert(newTerritory); // success
_shipperService.Insert(newShipper); // error
In this case you've partially committed the data, leaving the system in a bit of an unknown state.
Which object in this scenario is in control over the atomicity of the operation? In web applications I think that's usually the controller. The operation, after all, is the request made by the user. In most scenarios (there are exceptions, of course) I imagine one would expect the entire request to succeed or fail.
If this is the case and your atomicity belongs at the request level then what I would recommend is getting the DbContext from the IoC container at the controller level and passing it to the services. (They already require it on their constructors, so not a big change there.) Those services can operate on the context, but never commit the context. The consuming code (the controller) can then commit it (or roll it back, or abandon it, etc.) once all of the services have completed their operations.
While different business objects, services, etc. should each internally maintain their own logic, I find that usually the objects which own the atomicity of operations are at the application level, governed by the business processes being invoked by the users.
You're basically creating a repository here, rather than a service.
To answer your question you could just ask yourself another question. "How will I be using this functionality?"
You're adding a couple of records, removing some records, updating some records. We could say that you're calling your various methods about 30 times. If you call SaveChanges 30 times you're making 30 round-trips to the database, causing a lot of traffic and overhead which COULD be avoided.
I usually recommend doing as few database round-trips as possible, and limit the amount of calls to SaveChanges(). Therefore I recommend that you add a Save() method to your repository/service layer and call it in the layer which calls your repository/service layer.
Unless it is absolutely required to save something before doing something else you shouldn't call it 30 times. You should call it 1 single time. If it is necessary to save something before doing something else you could still call SaveChanges in that absolute moment of requirement in the layer calling your repository/service layer.
Summary/TL;DR: Make a Save() method in your repository/service layer instead of calling SaveChanges() in each repository/service method. This will boost your performance and spare you the unnecessary overhead.

ASP.NET MVC + EF Performance

I have this code in my Controller:
public class MyController : Controller
{
private readonly IMyRepository myRepository;
public MyController() : this(new MyRepository())
{}
public MyController(IMyRepository myRepository)
{
this.myRepository = myRepository;
}
public ActionResult Index()
{
return View(myRepository.GetData());
}
}
MyRepository uses EF for data operations. Every time user loads this page instance of MyRepository is creating. That means EF context is creating and Fluent API code is executing (OnModelCreating method).
Are there any possibilities not to create EF context everytime when user loads the page?
MyRepository uses EF for data operations. Every time user loads this
page instance of MyRepository is creating. That means EF context is
creating and Fluent API code is executing (OnModelCreating method).
You're wrong. Put a breakpoint on your OnModelCreating method. This method will only get hit once, when your application loads. It will hit the breakpoint again if you rebuild the project, because this causes the binary dll to be reloaded into the app domain. However if you leave the application running and hit the controller action twice (without rebuilding in between), you will see that OnModelCreating does NOT get hit the second time. Like Serg Rogovtsev says, EF caches the model (meaning the schema) after it is created during OnModelCreating.
The only objection I have to Serg Rogovtsev's answer is that I would never create a singleton instance of the DbContext. Instead you should use one instance per HttpContext (a.k.a. per web request). If you use it as a singleton, and you have concurrency enabled, you would end up seeing DbConcurrencyExceptions creep up in your app. Use DI/IoC, and create/dispose the DbContext instance at the beginning/end of the request response cycle. That is the best practice. Don't worry about the overhead of creating a new MyDbContext() instance. After EF initializes (warms up) during the first construction, future constructions will be fairly cheap.
To answer your question: you can create a singleton of your repository or you can use DI container which will hold single instance for you.
But to the point: if you set breakpoint inside OnModelCreating you will find that it gets called only once per application instance. EntityFramework uses pretty effective model caching. So you don't have to worry about performance hit caused by creation of EF contexts.
Change your controller so you create an instance of your repository in a lazy way. You can use the Lazy < T > class for example.
In terms of performance I'd favour looking to persist data and not the context, the EF context is optimized to be created and then disposed to free up connections in the pool.
Some other EF performance methods at http://www.sql-server-performance.com/2012/entity-framework-performance-optimization/
Best practice is to dispose the EF context after you've retrieved/updated your data.

Categories