Как использовать AddDbContextPool, если все настройки в методе OnConfiguring для DbContext - PullRequest
4 голосов
/ 23 апреля 2019

Я использую 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));

Но я хочу сохранить.UseNpgsql и другие конфиги DbContext в методе OnConfiguring.Как этого добиться?

1 Ответ

7 голосов
/ 30 апреля 2019

Помимо спорных преимуществ его использования (из документации: "имеет преимущество, заключающееся в экономии некоторых затрат на инициализацию экземпляра DbContext" ), пул DbContext простонеприменимо в вашем сценарии, потому что ваш контекст содержит состояние , о котором EF Core не знает:

private readonly DatabaseSettings _databaseOptions;

и раздел документации Limitations четко гласит:

Предупреждение!

Избегайте использования DbContext Pooling, если вы поддерживаете свое собственное состояние (например, частные поля) в производном классе DbContext, который не должен использоваться совместноЗапросы.EF Core сбросит только то состояние, о котором известно, перед добавлением экземпляра DbContext в пул.


Существует причина, по которой требуется optionsAction из AddDbContextPool, тогда как для AddDbContext это необязательно.Это связано с вышеупомянутым ограничением и дополнительным требованием, чтобы ваш производный класс DbContext имел открытый конструктор single с параметром single DbContextOptions.Вы можете легко увидеть это, обманув AddDbContextPool пропуская пустое действие:

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

, но затем во время выполнения вы получите InvalidOperationException, говорящее

DbContext типа«ApplicationDbContext» не может быть объединен в пул, потому что у него нет ни одного открытого конструктора, принимающего один параметр типа 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 должен быть настроен извне.

Другими словами, ваши требования взаимоисключающие, поэтому решения не существует.

...