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?
AddDbContextPool<TContext>(IServiceCollection, Action<DbContextOptionsBuilder>, Int32) Registers the given DbContext as a service in the IServiceCollection, and enables DbContext pooling for this registration. DbContext pooling can increase performance in high-throughput scenarios by re-using context instances.
The AddDbContext extension method registers DbContext types with a scoped lifetime by default.
When registering multiple DbContext types make sure that the constructor for each context type has a DbContextOptions parameter rather than a non-generic DbContextOptions parameter.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With