Transactions and the.NET Entity Framework

.net entity-framework sql-server-2005


I'm unfamiliar with the Entity Framework, therefore I'm not sure how to handle this particular combination of problems. The EF model is deeply interwoven across the whole site on the project I'm presently working on. At initially, a bootstrapper for Dependency Injection was used to regulate access to the EF environment. We were unable to utilize a DI library due to operational issues. When necessary, I eliminated this and utilized a model of distinct context object instances. I began seeing the following exception:

The type 'XXX' has been mapped more than once.

We got to the conclusion that this problem was being caused by the many context-specific instances. The context object was then abstracted into a single static instance that was used by each thread and page. I'm now receiving one of many transactions exceptions:

New transaction is not allowed because there are other threads running in the session.

The transaction operation cannot be performed because there are pending requests working on this transaction.

ExecuteReader requires the command to have a transaction when the connection assigned to the command is in a pending local transaction. The Transaction property of the command has not been initialized.

The last of these errors happened during a load process. On the thread that failed, I wasn't attempting to store the context state back to the database. However, such an operation was being carried out by another thread.

Although these exceptions are at best sporadic, I have been able to force the website to enter a condition where new connections were denied as a result of a transaction lock. Unfortunately, I can't identify the specifics of the exception.

My first question, I suppose, is if the EF model should be utilized from a static single instance. Is it also feasible to do away with the need for transactions in EF? I've experimented with aTransactionScope object unsuccessfully

To be quite honest, I'm very lost here and don't see why such basic tasks are creating such a problem.

11/22/2014 10:38:02 AM

Accepted Answer

establishing a single, global Entity FrameworkDbContext is particularly awful in a web application. TheDbContext class is not thread-safe (and Entity Framework v1's is the same).ObjectContext class). It is designed around the idea of the piece of work, so you only utilize it for one use case, which is a commercial transaction. It's designed to handle only one request at a time.

The reason you get the error is because you generate a new transaction for each request while attempting to utilize the sameDbContext . You're fortunate that theDbContext throws an exception when it notices this since it has now become clear that this won't work.

Please consider the reasons why this cannot work. TheDbContext includes a local cache of the database's entities. It enables you to make a lot of adjustments before submitting them to the database. When using a solitary staticDbContext when many people are phoningSaveChanges How is it expected to know precisely what should be committed and what shouldn't on that object?

It will store the modifications since it is unsure, but another request could still be making changes at that moment. If you're fortunate, the entities will be in an invalid state, causing either EF or your database to crash. If you're unfortunate, things that are in an invalid state are successfully saved to the database, and weeks later you can discover that your database is stuffed with garbage.

Your issue may be resolved by dialing (make a minimum of oneDbContext as requested). Although it is theoretically possible to store an object context in the user session, doing so is a poor idea since theDbContext usually last too long and include outdated information (because its internal cache will not automatically be refreshed).

Note as well that having oneDbContext each thread is equivalent to running the whole web application in a single instance. Because ASP.NET employs a thread pool, only a certain number of threads may be generated at any one moment for a given online application. Essentially, this indicates that thoseDbContext Instances would then continue to exist for the duration of the application, resulting in the same issues with stale data.

You may believe possessing oneDbContext every thread is really thread-safe, although this is often not the case since ASP.NET's asynchronous paradigm permits requests to be completed on threads other than the one on which they were initiated (and the latest versions of MVC and Web API even allow an arbitrary number of threads handle one single request in sequential order). As a result, the thread that initiated the request and produced theObjectContext long before the first request is done, become accessible to handle another request. However, the objects used in that request (such a web page, controller, or other business class) may still make reference to it.DbContext . The new web request will get the same response since it operates in the same thread.DbContext similar instance that the previous request is utilizing. This again introduces race conditions into your program and has the same negative effects on thread safety.DbContext specific causes.

7/15/2019 3:14:42 PM

Popular Answer

I'm going to presume that this is a web application as you mention the "site" in your query. Static members only exist once for the duration of the whole program, and if you use the singleton design pattern with a single context instance for the entire application, all requests will be in all possible states.

One static context instance won't do, and it won't be possible to mix and match contexts if there are numerous context instances per thread. You need a separate context for each thread. With the help of a dependency injection-style approach, we accomplished this in our application. Our BLL and DAL classes accept a context as a method argument, allowing you to do the following:

using (TransactionScope ts = new TransactionScope())
    using (ObjectContext oContext = new ObjectContext("MyConnection"))
        oBLLClass.Update(oEntity, oContext);

You just send the same context around if you need to contact additional BLL/DAL methods inside your update (or whichever method you choose). Since everything within a single method uses the same context instance and no other threads are utilizing it, updates, inserts, and deletes are atomic in this manner.

Related Questions


Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow