首页 > 解决方案 > 如果 DbContext 的 OnConfiguring 方法中的所有配置,如何使用 AddDbContextPool

问题描述

我正在使用 PostgreSQL,我有 ApplicationDbContext 像:

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);
            });
        }
    }
}

这种背景是许多其他人的基础。我正在改进性能并尝试使用上下文池。文档说要添加投票,我应该:

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

但我想在 OnConfiguring 方法中存储.UseNpgsql 和 DbContext 的其他配置。如何做到这一点?

标签: c#entity-frameworkentity-framework-coreef-core-2.2

解决方案


除了使用它的有争议的好处(来自文档:“具有节省初始化 DbContext 实例的一些成本的优势”)之外,DbContext 池在您的场景中根本不适用,因为您的上下文包含EF Core 的状态不知道:

private readonly DatabaseSettings _databaseOptions;

并且文档的限制部分明确指出:

警告!

如果您在派生的 DbContext 类中维护自己的状态(例如,私有字段),不应在请求之间共享,请避免使用 DbContext 池。EF Core 只会重置在将 DbContext 实例添加到池之前知道的状态。


optionsAction需要of是有原因的AddDbContextPool,而 forAddDbContext它是可选的。这是由于上述限制,以及DbContext派生类必须具有单个公共构造函数和单个 DbContextOptions参数的附加要求。AddDbContextPool您可以通过传递空操作来轻松地看到这一点:

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

但是在运行时你会InvalidOperationException

'ApplicationDbContext' 类型的 DbContext 不能被池化,因为它没有一个接受 DbContextOptions 类型的单个参数的公共构造函数。

所以为了有资格获得池,你必须删除所有这些

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

并添加这个

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

现在您应该清楚地看到为什么您所要求的内容是不可能的。您的OnConfiguring方法需要DatabaseSettings,但您无法提供它。因此options必须在外部进行配置。

换句话说,您的要求是相互排斥的,因此没有解决方案。


推荐阅读