'How does entity framework's DbContext & connection pooling work and what are its limitations?

From the documentation of MSDN on DbContext and DbContext pooling:

DbContext pooling has a few limitations on what can be done in the OnConfiguring method of the context.

Avoid using context pooling in apps that maintain state. For example, private fields in the context that shouldn't be shared across requests. EF Core only resets the state that it is aware of before adding a context instance to the pool.

Can you provide a concrete example on how these limitations would work?



Solution 1:[1]

Special thanks to Andrew Williamson for his splendid edit:


So this:

Avoid using context pooling in apps that maintain state. For example, private fields in the context that shouldn't be shared across requests. EF Core only resets the state that it is aware of before adding a context instance to the pool.

Basically states, that if you use private fields in your DbContext, like _myPrivateField, or a private property for that matter, and you use this to do some calculations - using context pooling might result in undesired behavior because you don't know what the initial value will be.

As an example, let's say you have a requirement to log the total number of rows affected during your request. The easiest way to do this would be to override the DbContext to track this:

public class FooContext : DbContext
{
    public DbSet<Foo> Foos { get; set; }

    public int Updates { get; private set; } = 0;

    public override int SaveChanges()
    {
        Updates += base.SaveChanges();
    }
}

Now if we turn on context pooling:

  • Request 1 creates a new FooController, which gets a new DbContext
  • Request 1 updates a Foo and saves changes, which increments the Updates value by 1
  • Request 1 logs the message 1 rows affected
  • Request 2 creates a new FooController, which reuses the same DbContext
  • Request 2 updates a Foo and saves changes, which increments the Updates value by 1
  • Request 2 logs the message 2 rows affected, which is not right

Entity Framework resets the things that it knows about before giving out a pooled DbContext, but since Updates is a custom variable, it doesn't know to reset it.

This one is easier:

Context pooling is intended for scenarios where the context configuration, which includes services resolved, is fixed between requests. For cases where Scoped services are required, or configuration needs to be changed, don't use pooling.

Simply states that if you need different configuration options for each DbContext - pooling is not able to help due to the re-use of the DbContext (and hence, the configuration). An example of this might be a multi-tenant environment where each tenant has their own database:

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
    optionsBuilder.UseSqlServer(CurrentUser.Tenant.ConnectionString);
}

If context pooling is turned on, the connection string will be cached between requests, so a user might start seeing data from a tenant they don't belong to instead of their own data.


About connection pooling specific, the doc's state that:

Note that DbContext pooling is orthogonal to database connection pooling, which is managed at a lower level in the database driver.

In this sentence "orthogonal" is just a difficult way of saying DbContext pooling and connection pooling are independent of each other because connection pooling is handled by a different mechanism.


Here is a nice article which explains why pooling is helpful: https://neelbhatt.com/2018/02/27/use-dbcontextpooling-to-improve-the-performance-net-core-2-1-feature/

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1