How to use AddDbContextPool if all configuration in OnConfiguring method of DbContext

c# ef-core-2.2 entity-framework entity-framework-core

Question

I'm using PostgreSQL and I have ApplicationDbContext like:

public class ApplicationDbContext : DbContext
{
    private readonly DatabaseSettings _databaseOptions;
    public ApplicationDbContext() { }
    public ApplicationDbContext(IOptions<DatabaseSettings> databaseOptions)
    {            
        _databaseOptions = databaseOptions.Value;
    }
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.HasPostgresExtension("citext");
    }
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        if (_databaseOptions == null)
        {
            optionsBuilder.UseInMemoryDatabase(Guid.NewGuid().ToString());
        }
        else
        {
            optionsBuilder.UseNpgsql(_databaseOptions.ConnectionString,
            npgsqlOptionsAction: sqlOptions =>
            {
                sqlOptions.EnableRetryOnFailure(
                    maxRetryCount: _databaseOptions.MaxRetryCount,
                    maxRetryDelay: TimeSpan.FromSeconds(_databaseOptions.MaxRetryDelay),
                    errorCodesToAdd: null);
            });
        }
    }
}

That context is base for many others. I'm on a way of improvement performance and trying to use context pooling . Docs say to add polling I should:

services.AddDbContextPool<EmployeeContext>(options => options.UseNpgsql(connection));

But I want to store.UseNpgsql and other configs of DbContext in OnConfiguring method. How to achieve that?

1
5
5/2/2019 1:24:22 PM

Accepted Answer

Besides the debatable benefits of using it (from the docs: "has the advantage of saving some of the cost of initialization of DbContext instance"), the DbContext pooling is simply not applicable in your scenario, because your context contains state which EF Core is unaware of:

private readonly DatabaseSettings _databaseOptions;

and the Limitations section of the documentation clearly states:

Warning!

Avoid using DbContext Pooling if you maintain your own state (for example, private fields) in your derived DbContext class that should not be shared across requests. EF Core will only reset the state that is aware of before adding a DbContext instance to the pool.


There is a reason why optionsAction of AddDbContextPool is required, while for AddDbContext it is optional. It's because of the aforementioned limitation, plus the additional requirement that your DbContext derived class must have single public constructor with single DbContextOptions parameter. You can easily see that by fooling the AddDbContextPool with passing empty action:

services.AddDbContextPool<ApplicationDbContext>(options => { });

but then at runtime you'll get InvalidOperationException saying

The DbContext of type 'ApplicationDbContext' cannot be pooled because it does not have a single public constructor accepting a single parameter of type DbContextOptions.

So in order to be eligible for pooling, you have to remove all these

private readonly DatabaseSettings _databaseOptions;
public ApplicationDbContext() { }
public ApplicationDbContext(IOptions<DatabaseSettings> databaseOptions)
{            
    _databaseOptions = databaseOptions.Value;
}

and add this instead

public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options) { }

Now you should clearly see why what you are asking is not possible. Your OnConfiguring method requires DatabaseSettings, but there is no way you could provide it. Hence the options must be configured externally.

In other words, your requirements are mutually exclusive, hence there is no solution.

8
5/3/2019 7:27:37 PM


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow