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.
Related
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)
I'm currently using TransactionScope to manage transactions in my data layer, but I've been running into issues with nested transactions and async whereby the connection seems to close during the nested transaction or the transaction is promoted to MSDTC. I've not found the exact problem but after reading around it looks like this scenario isn't particuarly well supported and that I should be using Database.BeginTransaction() instead.
My problem is that I can't find information on how Database.BeginTransaction() works with nested transactions, particularly in my scenario where i'm wanting to use the ambient transaction rather than create a new one. My suspicion is that it isn't intended to work this way and if I want to manage nested transactions I should abstract out transaction management to give me more control.
Not wanting to add in unnecessary layers of abstractions I wanted to know if anyone has experience in this area and could confirm the behavior of Database.BeginTransaction() when nested inside another transaction?
Additional information about my DAL: Based on CQS pattern, I tend to encapsulate Db related code in command or query handlers, so a simplified/contrived example of how this nesting occurs would be:
public class AddBlogPostHandler
{
private readonly MyDbContext _myDbContext;
public AddBlogPostHandler(MyDbContext myDbContext)
{
_myDbContext = myDbContext;
}
public async Task ExecuteAsync(AddBlogPostCommand command)
{
using (var scope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
{
// .. code to create and add a draft blog post to the context
await _myDbContext.SaveChangesAsync();
var publishBlogPostCommand = new PublishBlogPostCommand();
// ..set some variables on the PublishBlogPostCommand
await PublishBlogPostAsync(command);
scope.Complete();
}
}
}
public class PublishBlogPostHandler
{
private readonly MyDbContext _myDbContext;
public PublishBlogPostHandler(MyDbContext myDbContext)
{
_myDbContext = myDbContext;
}
public async Task ExecuteAsync(PublishBlogPostCommand command)
{
using (var scope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
{
// .. some code to do one set of update
await _myDbContext.SaveChangesAsync();
// .. some other db updates that need to be run separately
await _myDbContext.SaveChangesAsync();
scope.Complete();
}
}
}
There is no such thing as nested transactions in the sense that the inner one can commit or rollback independently. Nested transactions really only maintain a ref count. At the last commit we get a physical commit. At the first rollback we get a physical rollback. Just making sure you are aware of that.
It is important to avoid MSDTC usage. This is possible both with TransactionScope and with BeginTransaction. With the former you need to explicitly Open the connection inside the scope so that EF does not open new connections all the time.
As you have read in the issue this is a flaw in EF (which L2S did not have). Please take the time to comment on the issue to make sure the team is aware that customers are running into this problem.
particularly in my scenario where i'm wanting to use the ambient transaction rather than create a new one.
This is perfect for TransactionScope. I think your switch to BeginTransaction is based on a misunderstanding. Maybe you can clarify in the comments.
confirm the behavior of Database.BeginTransaction() when nested inside another transaction
Explained in the first paragraph.
Additional information about my DAL: Based on CQS pattern, I tend to encapsulate Db related code in command or query handlers, so a simplified/contrived example of how this nesting occurs would be:
The code looks fine except for the missing db.Connection.Open() call (as explained above).
This pattern will support executing multiple queries and commands in the same transaction. Just wrap another scope around it. Make sure to not open connections twice, e.g. check conn.State before taking action.
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.
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.
I'm building a Webforms EF6 database first application and am not sure how best to manage DbContext. I looked at a lot of tutorials and forum posts but I'm still sure. Regarding the much favored 'using per request', I've not found a way to save parent & children in one go. I got it to work with the code below, but where and when would I dispose of the context? Can I use this approach? Would the per request approach by Kamyar shown here be better?
Here's what I've got now:
public static class ContextManager
{
[ThreadStatic]
private static MyContext current;
public static MyContext MyCurrentContext
{
get{
if (current == null)
current = new MyContext();
return current;
}}
}
coupled with
var context = ContextManager.MyCurrentContext;
.....
context.SaveChanges();
Thanks in advance for any help!
A specific example would be 'UserProfile' which contains child objects as properties such as 'DefaultInvoiceAddress' which returns the user's default invoice address from a table with all the user's addresses. In the last web application I worked on, when user edits this address from within the profile (e.g. street change), together with other profile information from other tables, EF would save all edited information from the different tables in one request (ensuring they're attached). Since I wasn't privy to the context management, I don't know how it was done, but we would always assign a common current context for the requests.
I came across this post by Rick Strahl, and this one by Jordan van Gogh - the business object / transaction seem to be an answer, but I don't quite understand how to implement it and couldn't find an example. The 'shared ObjectContext instance per HTTP request' corresponds to Kamyar's answer mentioned above, and all things considered, it sounds a good option. Would I have to explicitly dispose of the context, if so when/where?. Are there any drawbacks?
Bad idea. Static is totally against the best practices. No 2 users ever will use the app at the same time? Ouch. For WebForms.
Per request IS the best choice.
The EF db context object is not, I repeat NOT threadsafe no matter how you manage it. Lots of problems can arise from sharing a db context across threads so the best way is, as mentioned above to use it per request.
If you don't want to jump into the IoC/DI side of things a really simple way to do it is whenever you need the database you just instantiate your context in a using block, like so:
using(var db = new MyContext())
{
// code reading from/writing to database
...
...
}
Using singleton pattern with entity framework database context is a design defect specially if you work with concurrency environment such as web forms because you have to take in your consideration that DbContext is not thread safe object.