Reputation: 123
I read a lot of documents and articles about DBcontext in Efcore and its lifetime, however, I have some questions.
Based on this link "https://learn.microsoft.com/en-us/ef/core/dbcontext-configuration/" the best lifetime of DBcontext and default lifetime of AddDbContext is scope, but there is a contradiction in the two below sentences on this document.
"DbContext is not thread-safe. Do not share contexts between threads. Make sure to await all async calls before continuing to use the context instance."
on the other hand, it was mentioned too,
"Dbcontext is safe from concurrent access issues in most ASP.NET Core applications because there is only one thread executing each client request at a given time, and because each request gets a separate dependency injection scope (and therefore a separate DbContext instance)."
In addition, I read some docs that prohibit registering singleton DbContext, however, AddDbContextPool makes to register singleton DBcontext. so there are some questions about the Dbcontextpool.
One DbContext per web request... why?
.NET Entity Framework and transactions
Upvotes: 10
Views: 9820
Reputation: 172606
I understand why you think the language in the Microsoft documents is confusing. I'll unravel it for you:
DbContext
from multiple threads in parallel. The stack overflow answers you already referenced, explain this.DbContext
is shared between (web) requests.DbContext
instances are thread-safe, which they aren't. What the writers mean to say here is that, with the default configuration (i.e. using AddDbContext<T>()
, ASP.NET Core ensures that each request gets its own DbContext
instance, making it, therefore, "safe from concurrent access" by default.1 I was confused about whether registering DBcontext as a scoped service is thread-safe or not?
DbContext instances are by themselves not thread-safe, which is why you should register them as Scoped
, because that would prevent them from being accessed from multiple requests, and thus in parallel.
This doesn't prevent you from spinning of (background) operations from within a single request all accessing the DbContext
instance in parallel. This could happen when you use Parallel.ForEach
or when you forget to await an asynchronous operation (causing it to run in parallel in the background). These types of situations should be prevented because, again, DbContext
is not thread-safe.
2 What are the problems of registering DBcontext as a singleton service in detail?
This is already described in detail in this answer, which you already referenced. I think that answer goes into a lot of detail, which I won't repeat here.
In addition, I read some docs that prohibit registering singleton DbContext, however, AddDbContextPool makes to register singleton DBcontext. so there are some questions about the Dbcontextpool.
The DbContext
pooling feature is very different from registering DbContext
as singleton, because:
DbContext
instance.DbContext
instances exist with pooling, while only a single instance for the whole application exists when using the Singleton lifestyle.DbContext
is 'cleaned' and brought back to the pool, so it can be reused by a new request.what are the impacts of using the DbContextPool instead of the DbContext?
More information about this is given in this document.
when we should use it and what should be considered when we use contextPool?
When your application requires the performance benefits that it brings. This is something you might want to benchmark before deciding to add it.
DbContextPool is thread-safe?
Yes, in the same way as registering a DbContext
as Scoped
is thread-safe; in case you accidentally hold on to a DbContext
instance inside an object that is reused across requests, this guarantee is broken. You have to take good care of Scoped
objects to prevent them from becoming Captive Dependencies.
Has it memory issues because of storing a number of dbset instances throughout the application's lifetime?
The memory penalty will hardly ever be noticeable. The so-called first-level cache is cleared for every DbContext
that is brought back to the pool after a request ends. This is to prevent the DbContext
from becoming stale and to prevent memory issues.
change-tracking or any parts of the ef would be failed or not in the DB context pool?
No, it doesn't. For the most part, making your DbContext
pooled is something that only requires infrastructural changes (changes to the application's startup path) and is for the most part transparent to the rest of your application. But again, make sure to read this to familiar yourself with the consequences of using DbContext
pooling.
Upvotes: 13