Entity Framework - concurrent use of containers - c#

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.

Related

Dependency injection of multiple Entity Framework Core Contexts for running queries in parallel

I have a web application using Entity Framework Core 3.1 and the DbContext is registered using services.AddDbContext at the start.
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<MyProjectContext>(options =>
{
...
});
}
}
I need to run multiple queries in parallel, but Entity Framework only allows one asynchronous query at a time. By reading other answers here on SO I think I need to have multiple instances of MyProjectContext and run one query per instance.
What I don't know to do is how to register multiple instances of my DbContext and how to retrieve them in my controllers.
public class ProductsController : ControllerBase
{
public ProductsController(MyProjectContext context1, MyProjectContext context2, MyProjectContext context3)
{
var product = context1.Products.AsNoTracking().FirstAsync();
var category = context2.Categories.AsNoTracking().FirstAsync();
var customer = context3.Customer.AsNoTracking().FirstAsync();
// Task.WaitAll, etc.
}
}
context1, context2, and context3 are resolving to the same instance.
How can I have each DbContext to resolve to a different instance - and at the same time have them be scoped to the request?
This code would await each call before calling the next regardless of one DbContext or three:
public ProductsController(MyProjectContext context1, MyProjectContext context2, MyProjectContext context3)
{
var product = await context1.Products.AsNoTracking().FirstAsync();
var category = await context2.Categories.AsNoTracking().FirstAsync();
var customer = await context3.Customer.AsNoTracking().FirstAsync();
}
To kick them off in parallel it would look like:
var productTask = context1.Products.AsNoTracking().FirstAsync();
var categoryTask = context2.Categories.AsNoTracking().FirstAsync();
var customerTask = context3.Customer.AsNoTracking().FirstAsync();
await Task.WhenAll(productTask, categoryTask, customerTask);
var product = productTask.Result;
var category = categoryTask.Result;
var customer = customerTask.Result;
However, since your contexts are resolving to the same instance, this would result in multi-thread access exceptions from the DbContext.
One option would be to supply a DbContextFactory for classes where you want more manual control over the lifetime scope of the DBContext.
public ProductsController(MyProjectContextFactory contextFactory)
{
using(var context1 = contextFactory.Create())
{
using(var context2 = contextFactory.Create())
{
using(var context3 = contextFactory.Create())
{
var productTask = context1.Products.AsNoTracking().FirstAsync();
var categoryTask = context2.Categories.AsNoTracking().FirstAsync();
var customerTask = context3.Customer.AsNoTracking().FirstAsync();
await Task.WhenAll(productTask, categoryTask, customerTask);
var product = productTask.Result;
var category = categoryTask.Result;
var customer = customerTask.Result;
}
}
}
}
I don't generally recommend considering approaches like this to parallelize queries because it is important to consider that each of these three objects are coming from separate DbContexts so the cannot be relied on as references for anything that will be persisted to any one other DbContext. Within the scope of these using blocks, these entities will be proxies that are tracked by their respective DbContext, so referencing them to update another entity (on another DbContext) will result in an exception. Outside of the scope of these contexts these entities will need to be checked against another DbContext before being attached to it.
The other option is to change your Dependency Injection lifetime scope for the DbContext to Per Instance or such rather than something like Per Web Request. Configuring this would depend on the DI framework you are using. (I.e. Autofac or Unity, etc) The caveat of this though is that all DbContext instances would be separate from one another which would lead to all kinds of problems like above where normally things like Controllers and Services etc. that might reference a DbContext would be provided a single instance tracking the entities retrieved so those entities could be associated etc. with one another without issue. If the DbContexts are all switched to be provided Per Instance (per request from the DI container) then this could lead to all kinds of exceptions and duplicate rows being inserted etc.
What issue/concern are you facing where you believe you need parallelization of queries? Loading Entities by ID is extremely fast, to the point that unless you are including a lot of related entities, it is generally better to leave these operations as synchronous queries. async itself adds a small performance hit, so it is not a performance silver bullet. The main purpose of async operations is to free up the server thread to respond to other requests while a particularly heavy client request is being processed. This doesn't make an individual request faster, but overall ensures your server stays responsive to kick off more requests. Parallelizing requests can potentially make a client request complete faster, but involves significantly more complexity to ensure the appropriate response comes back, and handle objects tracked by separate DbContexts. It's something I'd only consider where I am certainly facing a performance issue on a case-by-case basis, not something I'd pursue as a convention to try and preemptively tackle an imaginary performance issue. (async queries add a small performance hit, and add complexity & potential issues down the road especially when intermixing parallelization)

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.

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.

Context duplication on nested call to linq operations

I have refactored some querys on linq in order to have two calls:
public IQueryable<Entity> GetAll()
{
return context.Set<ENTITY>().Project().To<Entity>();
}
That is called from:
public int FindLastID()
{
using(var context = new DBContext())
{
return GetAll().Max(p => p.id);
}
}
The problem is that GetAll should be independently used, and it has no context. If the using context in wirtten on the GetAll method it is disposed and the Max function generates an excetion.
Is any way of calling the GetAll with no exception?
Usually all repository methods assume that a context is created. This is the most convenient way. So your FindLastID method also shouldn't create the context, unless it's a service layer method. One simple example is to use a static variable:
public void AServiceMethod()
{
using (var context = contextProvider.CreateContext())
{
// call some domain operations, which use repositories
// commit
}
}
Where CreateContext will open a DB session and store it in some static variable accessible from all repositories. This is not very elegant, but often is sufficient. To make it better you can use IoC as suggested by Sergey Berezovskiy. Also you may be interested in this article, recommended by Sam Leach in his answer.
Alternatively you could try something like this:
public IQueryable<Entity> GetAll()
{
return GetAll(null);
}
public IQueryable<Entity> GetAll(DBContext context)
{
if (context == null)
{
using (context = new DBContext())
{
return GetAll(context);
}
}
return context.Set<ENTITY>().Project().To<Entity>();
}
But I'd recommend the first approach, as it's simpler and easier to maintain, comprehend.
This question is about Entity Framework Context Management.
See this MSDN article, Working with DbContext
It gives some general guidelines that you might find useful while thinking about refactoring and designing your data access.
When working with long-running context consider the following:
As you
load more objects and their references into memory, the memory
consumption of the context may increase rapidly. This may cause
performance issues.
Remember to dispose of the context when it is no
longer required.
If an exception causes the context to be in an
unrecoverable state, the whole application may terminate.
The chances
of running into concurrency-related issues increase as the gap between
the time when the data is queried and updated grows.
When working with Web applications, use a context instance per request.
When working with Windows Presentation Foundation (WPF) or Windows Forms, use a
context instance per form. This lets you use change-tracking
functionality that context provides.
Using an IoC framework to manage the lifetime of your context is probabably the best approach as Sergey Berezovskiy said.
Also, see this old (but good) article about context lifetime management.

session state variables and singleton class

I have a situation where I need to retrieve data from a query which executes for almost half a minute and bring it to a web page. (There is no way to reduce this time because the maximum amount of optimization has been performed on it)
I use a four layer architecture along with Entity Framework ( EF, Data Access Layer, Biz Logic Layer, UI) for my application.
I'm trying to use the singleton method when an instance to the DAL is created (The DAL in turn retrieves data from the database) so that I will be able to re-use this instance and hence additional instances wont be created within the same session.
How do I go about setting the session state and checking the availability of the instance in the State Server?
public static Singleton getInstance() {
if (**instance == null**)
instance = new Singleton();
return instance;
}
What should reside within the if block? What condition should I check for in the if block? I'm really unsure as to what I must do.
PS: This session must have a timeout of 5 mins. I hear this can be specified in the Web.config file. is it true?
To be honest you should rather use Entity Framework context and create it every time you need access to database, i.e. in each method. It is optimized to be used that way. Connection pooling will make sure there is not penalty in recreating EF context each time. This is the best practice.
But your DAL might be more than just simple DB access. If you want to have it as a singleton separate for each session you must create the instance on the first request, store it into the Session and check if it's there before using. With thread safety the code could look like that:
class DALClass
{
private static object instanceLock = new object();
public static DALClass Instance
{
get
{
if (Session["DALInstance"] == null)
{
lock (instanceLock)
{
if (Session["DALInstance"] == null)
{
Session["DALInstance"] = new DALClass();
}
}
}
return (DALClass)Session["DALInstance"];
}
}
}
It sounds to me like you have a well defined architecture which would suit dependency injection. Using DI you could just get your IOC container to return you a singleton object or a transient one. However, be very careful using singletons in a web environment as they often cause more trouble than they are worth.
If the query you are running contains user specific data then I would probably place the results of that query into session within the code which composes the UI part of your application if you are using a pattern like MVC that would be in the controller or MVP in the presenter.
If these patterns aren’t in use then you could consider placing the information into session inside the business layer but only if you wrap up the session and inject in that dependency into your business object, e.g. something like “IUserSession”. The business project should not contain a reference to “system.Web” or anything like that.

Categories