Entity Framework Core Проблема наследования DbContext с DbOptions в конструкторе - PullRequest
0 голосов
/ 11 февраля 2019

В нашем проекте у нас есть база данных, в которой мы используем первый подход к БД.Поскольку мы используем функции, которые не получают scaffolded, у меня есть второй DBContext, который наследует от сгенерированного.Это позволяет мне избегать ручного манипулирования сгенерированным контекстом БД при каждом изменении базы данных.

Таким образом, определения и использование классов в StartUp выглядит следующим образом:

  // the db context generated by scaffolding the database
  public partial class ApplicationDatabaseContextGenerated : DbContext
  {
    public ApplicationDatabaseContextGenerated() {}
    public ApplicationDatabaseContextGenerated(DbContextOptions<ApplicationDatabaseContextGenerated> options) : base(options) {}

    // the db sets scaffolded
  }

  // the db context used by the app with the extended functionality
  public class ApplicationDatabaseContext : ApplicationDatabaseContextGenerated
  {

    public ILogger<ApplicationDatabaseContext> Logger { get; protected set; }

    public ApplicationDatabaseContext() : base() {}

    public ApplicationDatabaseContext(DbContextOptions<ApplicationDatabaseContext> options, ILogger<ApplicationDatabaseContext> logger) : base(options)
    {
      Logger = logger ?? throw new ArgumentNullException(nameof(logger));
    }

    // the extended functionality like views and functions

  }

  // how I use it in startup
  public void ConfigureServices(IServiceCollection services)
  {
    // other things ...

    services.AddDbContext<ApplicationDatabaseContext>(options => options.UseNpgsql(Configuration.GetConnectionString("db1-connection")));

    // other things ...
  }

К сожалению, это приводит к компиляцииошибка при выделении базы (опций) конструктора ApplicationDatabaseContext:

Error CS1503 Argument 1: cannot convert from 'Microsoft.EntityFrameworkCore.DbContextOptions<... ApplicationDatabaseContext>' to 'Microsoft.EntityFrameworkCore.DbContextOptions<... ApplicationDatabaseContextGenerated>'

Я подумал, давайте будем умными, ApplicationDatabaseContextGenerated в основном является контекстом базы данных и изменил конструктор ApplicationDatabaseContextGenerated на:

  public ApplicationDatabaseContextGenerated(DbContextOptions<DbContext> options) : base(options) {}

Нет, это тоже не разрешено и приводит к:

Error CS1503 Argument 1: cannot convert from 'Microsoft.EntityFrameworkCore.DbContextOptions<... ApplicationDatabaseContext>' to 'Microsoft.EntityFrameworkCore.DbContextOptions<Microsoft.EntityFrameworkCore.DbContext>'

Хорошо, давайте возьмем оба в качестве DbContext

  // the db context generated by scaffolding the database
  public partial class ApplicationDatabaseContextGenerated : DbContext
  {
    public ApplicationDatabaseContextGenerated() {}
    public ApplicationDatabaseContextGenerated(DbContextOptions<DbContext> options) : base(options) {}

    // the db sets scaffolded
  }

  // the db context used by the app with the extended functionality
  public class ApplicationDatabaseContext : ApplicationDatabaseContextGenerated
  {

    public ILogger<ApplicationDatabaseContext> Logger { get; protected set; }

    public ApplicationDatabaseContext() : base() {}

    public ApplicationDatabaseContext(DbContextOptions<DbContext> options, ILogger<ApplicationDatabaseContext> logger) : base(options)
    {
      Logger = logger ?? throw new ArgumentNullException(nameof(logger));
    }

    // the extended functionality like views and functions

  }

Довольно, что компилируется,Давайте начнем и получим:

  System.InvalidOperationException: No database provider has been configured for this DbContext. A provider can be configured by overriding the DbContext.OnConfiguring method or by using AddDbContext on the application service provider. If AddDbContext is used, then also ensure that your DbContext type accepts a DbContextOptions<TContext> object in its constructor and passes it to the base constructor for DbContext.
    at Microsoft.EntityFrameworkCore.Internal.DbContextServices.Initialize(IServiceProvider scopedProvider, IDbContextOptions contextOptions, DbContext context)
    at Microsoft.EntityFrameworkCore.DbContext.get_InternalServiceProvider()
    at Microsoft.EntityFrameworkCore.DbContext.get_DbContextDependencies()
    at Microsoft.EntityFrameworkCore.DbContext.get_Model()
    at Microsoft.EntityFrameworkCore.Internal.InternalDbQuery`1.get_EntityType()
    at Microsoft.EntityFrameworkCore.Internal.InternalDbQuery`1.get_EntityQueryable()
    at Microsoft.EntityFrameworkCore.Internal.InternalDbQuery`1.System.Linq.IQueryable.get_Provider()
    at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ExecuteAsync[TSource,TResult](MethodInfo operatorMethodInfo, IQueryable`1 source, CancellationToken cancellationToken)
    at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.SingleAsync[TSource](IQueryable`1 source, CancellationToken cancellationToken)
    at ... MyMethod(ApplicationDatabaseContext dbContext, CancellationToken cancellationToken) in myfile.cs:line 51
    at ... MyOtherMethod in myfile.cs:line 61

Ну, как преобразовать DbContextOptions или как наследовать DbContexts?

1 Ответ

0 голосов
/ 11 февраля 2019

DbContextOptions<TContext> - это обобщенный класс , и, как и любой другой класс, он не поддерживает ковариацию, следовательно, DbContextOptions<TDerivedContext> не может рассматриваться как DbContextOptions<TBaseContext>.

.используйте неуниверсальный класс DbContextOptions в конструкторе базового контекста (аналогично конструктору класса DbContext с опциями):

public ApplicationDatabaseContextGenerated(DbContextOptions options) : base(options) { }

Поскольку AddDbContext<ApplicationDatabaseContext> создаст экземпляркласса DbContextOptions<ApplicationDatabaseContext> конструктор класса ApplicationDatabaseContext может использовать либо опцию DbContextOptions<ApplicationDatabaseContext>, либо DbContextOptions.

...