When I implement an ASP.NET Core application, I may have several middlewares that must interact with the database in order to check something. All of them, and also the final endpoint, share a scoped DbContext
(because I configured the DbContext
's lifetime that way).
For example:
// /api/projects/create
How does the DbContext
's connection work? Is it shared among all the services and calls of the request? Or is it different for every single FirstOrDefault()
/ToList()
/SaveChanges()
called on the DbContext
?
If it's the same, is it also opened and closed one single time per scope, or for every single FirstOrDefault()
/ToList()
/SaveChanges()
(with all the overhead involved)?
If it's the latter, is there a way to configure a single Open()
/Close()
per scope, and would it be a good practice?
AFAIK EFCore uses connection pooling by default, so there isn’t “the” connection. In fact, EFCore doesn’t even handle the pooling but relies on the database driver:
EF does not implement connection pooling itself, but relies on the underlying database driver (e.g. ADO.NET driver) for managing database connections.
[…]
Pooling configuration must be performed at the driver level; for example, when using ADO.NET, parameters such as minimum or maximum pool sizes are usually configured via the connection string.
It further says:
EF generally opens connections just before each operation (e.g. query), and closes it right afterwards, causing it to be returned to the pool
Stupidly, “open” and “close” here just mean borrowing and returning to the pool. Indeed, when you manually call Open()
on a connection, this also just borrows a connection from the pool (provided one is available). The actual “opening” you hear about causing overhead is done by the driver and not directly exposed to you.
In any case, you shouldn’t need to care about any of this unless maybe you’re seeing issues specifically related to it.