команда add-migration не работает в ApplicationDbContex

Приложение: Asp.NET Core 1.1.1, EF Core.

Платформа: Visual Studio 2017 5.3.3.

Режим аутентификации: индивидуальные учетные записи пользователей

Следуйте этому руководству от ASP. NET, следующая команда выполняется успешно:

PM> Add-Migration MyFirstMigration -context BloggingContext

Как мы знаем, VS2017 по умолчанию создает ApplicationDbContext в папке MyProject \ Data для создания пользовательских таблиц (ASPNETUsers, ASPNETRoles etc...) для аутентификации. Но для этого, когда я запускаю следующую команду, она сначала дает мне Error-1 ниже. И когда я следую инструкциям в первом сообщении об ошибке, я получаю Error-2 ниже. Вопрос: Как заставить работать следующую команду без использования IDbContextFactory?

PM> Add-Migration MyFirstAuthenMigration -context ApplicationDbContext

Ошибка 1

В ApplicationDbContext не найден конструктор без параметров. Либо добавьте конструктор без параметров в ApplicationDbContext, либо добавьте реализацию IDbContextFactory в ту же сборку, что и ApplicationDbContext.

После добавления конструктора без параметров в ApplicationDbContext.cs (показано ниже) я получаю вторую ошибку, показанную ниже:

Ошибка 2

Для этого DbContext не настроен поставщик базы данных. Поставщика можно настроить, переопределив метод DbContext.OnConfiguring или используя AddDbContext в поставщике службы приложения. Если используется AddDbContext, также убедитесь, что ваш тип DbContext принимает объект DbContextOptions в своем конструкторе и передает его в базовый конструктор для DbContext.

ApplicationDbContext.cs

public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
    //NOTE: I added following constructor after Error 1 shown above
    public ApplicationDbContext()
    {
    }

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

    protected override void OnModelCreating(ModelBuilder builder)
    {
        base.OnModelCreating(builder);
        // Customize the ASP.NET Identity model and override the defaults if needed.
        // For example, you can rename the ASP.NET Identity table names and more.
        // Add your customizations after calling base.OnModelCreating(builder);
    }
}

person nam    schedule 04.09.2017    source источник
comment
Унаследован ли ваш класс BloggingContext от DbContext? Ваш класс ApplicationDbContext наследуется от IdentityDbContext ‹ApplicationUser›.   -  person Anthony McGrath    schedule 04.09.2017
comment
@AnthonyMcGrath 1. Да (то же, что показано в приведенном выше ссылка на учебное пособие). И первая команда PM работает нормально. 2. Да (как показано в приведенном выше классе ApplicationDbContext.cs)   -  person nam    schedule 04.09.2017
comment
Установлены ли у вас все необходимые пакеты слепков entity framework? Может, вместо этого вам следует унаследовать от DbContext? В связанном вами руководстве есть строка кода, которая вызывает метод AddDbContext () (метод, упомянутый в вашей ошибке 2). Возможно, вам потребуется вызвать этот метод. Также у вас настроены свойства DbSet ‹›?   -  person Anthony McGrath    schedule 04.09.2017
comment
@AnthonyMcGrath В startup.cs я заменил services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"))); на var connection = @"Server=MyMachine\SQLEXPRESS;Database=ForgotPswd;Trusted_Connection=True;"; services.AddDbContext<BloggingContext>(options => options.UseSqlServer(connection));. Это правильно?   -  person nam    schedule 04.09.2017
comment
Попробуйте использовать ApplicationDbContext вместо BloggingContext, поскольку ApplicationDbContext - это класс, который вы пытаетесь исправить. Или вы могли убедиться, что строка подключения DefaultConnection настроена правильно.   -  person Anthony McGrath    schedule 04.09.2017
comment
@AnthonyMcGrath Но часть BloggingContext в приведенном выше комментарии необходима, как указано в разделе Register your context with dependency injection документа ссылка. Я думаю, что путаница заключается в том, что связанный учебник не использует Authentication mode, в то время как я использую учебник, но с дополнительным шагом, который связан с Authentication mode. А для использования таблиц блогов и сообщений мне нужно, чтобы BloggingContext был зарегистрирован с Dependency Injection.   -  person nam    schedule 04.09.2017
comment
Вы регистрируете оба класса контекста с помощью внедрения зависимостей?   -  person Anthony McGrath    schedule 04.09.2017
comment
Позвольте нам продолжить это обсуждение в чате.   -  person nam    schedule 04.09.2017


Ответы (1)


Вы не можете заставить его работать. Потому что EF нужно знать, какую строку подключения следует использовать. Вы можете поместить строку подключения в свой метод OnModelCreating. Что плохо, когда у вас более одной БД (например, для разработки, тестирования и производства). Или вы реализуете IDbContextFactory, который будет загружен EF через отражение.

Так что реализация IDbContextFactory - лучший вариант. Просто создайте его там, где у вас есть ApplicationDbContext. Пример реализации.

public class DomainContextFactory : IDbContextFactory<DomainContext>
{
    public string BasePath { get; protected set; }

    public DomainContext Create()
    {
        var environmentName = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");
        var basePath = AppContext.BaseDirectory;
        return Create(basePath, environmentName);
    }

    public DomainContext Create(DbContextFactoryOptions options)
        => Create(options.ContentRootPath, options.EnvironmentName);

    private DomainContext Create(string basePath, string environmentName)
    {
        BasePath = basePath;
        var configuration = Configuration(basePath, environmentName);
        var connectionString = ConnectionString(configuration.Build());
        return Create(connectionString);
    }

    private DomainContext Create(string connectionString)
    {
        if (string.IsNullOrEmpty(connectionString))
        {
            throw new ArgumentException($"{nameof(connectionString)} is null or empty", nameof(connectionString));
        }
        var optionsBuilder = new DbContextOptionsBuilder<DomainContext>();
        return Configure(connectionString, optionsBuilder);
    }

    protected virtual IConfigurationBuilder Configuration(string basePath, string environmentName)
    {
        var builder = new ConfigurationBuilder()
            .SetBasePath(basePath)
            .AddJsonFile("constr.json")
            .AddJsonFile($"constr.{environmentName}.json", true)
            .AddEnvironmentVariables();
        return builder;
    }

    protected virtual string ConnectionString(IConfigurationRoot configuration)
    {
        string connectionString = configuration["ConnectionStrings:DefaultConnection"];
        return connectionString;
    }

    protected virtual DomainContext Configure(string connectionString, DbContextOptionsBuilder<DomainContext> builder)
    {
        builder.UseSqlServer(connectionString, opt => opt.UseRowNumberForPaging());
        DomainContext db = new DomainContext(builder.Options);
        return db;
    }

    DomainContext IDbContextFactory<DomainContext>.Create(DbContextFactoryOptions options)
        => Create(options.ContentRootPath, options.EnvironmentName);
}

Работает с 3-мя конфигурационными файлами (финальным, локальным и тестовым).

  • constr.dev-final.json
  • constr.dev-local.json
  • constr.dev-test.json

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

public override IServiceResult<IList<Rolle>> LoadAllData()
{
    using (var db = this.DomainContextFactory.Create())
    {
        Task<List<Rolle>> rollen = db.Roles
            .ToListAsync<Rolle>();
        return new ServiceResult<IList<Rolle>>(rollen.Result, rollen.Result.Count);

    }
}

И использование «Add-Migration» внутри MSVC тоже работает.

person user743414    schedule 05.09.2017