首页 > 解决方案 > 无法在 MySql DbContext 的 dotnet ef 迁移中创建对象错误,但适用于 Sqlite DbContext

问题描述

我为一个新的 ASP.Net Core 应用程序创建了 2 个 DbContexts。

https://github.com/jonasarcangel/IdentityMigrationsForMySql/tree/master/IdentityMigrationsForMySql/Server/Data

它们都派生自同一个 ApplicationDbContext 基类,唯一的区别是 OnConfiguring 覆盖,其中使用 UseMySql 而不是 UseSqlite,遵循本文中关于多个提供程序的建议。

SqliteDbContext.cs 有这个:

        protected override void OnConfiguring(DbContextOptionsBuilder options)
        {
#if DEBUG_EF
            options.UseSqlite("DataSource=");
#endif
        }

MySqlDbContext.cs 有这个:

        protected override void OnConfiguring(DbContextOptionsBuilder options)
        {
#if DEBUG_EF
            options.UseMySql("Server=");
#endif
        }

运行了以下命令:

dotnet ef migrations add InitialCreate --context MySqlDbContext --output-dir Migrations/MySql --configuration DebugEf

返回的错误是:

无法创建“MySqlDbContext”类型的对象。有关设计时支持的不同模式,请参阅 https://go.microsoft.com/fwlink/?linkid=851728

但是,以下使用 Sqlite 上下文的命令是成功的。

dotnet ef migrations add InitialCreate --context SqliteDbContext --output-dir Migrations/Sqlite --configuration DebugEf

标签: asp.netentity-frameworkasp.net-core

解决方案


这是因为在您的ConfigureServices方法中,您明确配置了 SqliteDbContext:

public void ConfigureServices(IServiceCollection services)
        {
            services.AddDbContext<SqliteDbContext>(options =>
                options.UseSqlServer(
                    Configuration.GetConnectionString("DefaultConnection")));
            ...
        }

如果您将代码更改为 ,这将成功创建迁移AddDbContext<MySqlDbContext>,但它会破坏 Sqlite 构建。

如果您继续阅读您链接的文章,他们将描述如何解决此问题:

在您的应用程序中,您应该继续使用MyDb. 但是,要让 EF 确定要使用哪个迁移,您必须调用 services.GetService<T>where T 是子类之一(而不是 MyDb)。

因此,在 中Startup.ConfigureServices,注册子类:

// Configure database 
switch (config.DbProvider.ToLower()) {
case "sqlite": {
    services.AddDbContext<MyDb>(options => { options.UseSqlite(config.DbConnString); });
    services.AddDbContext<SqliteMyDb>(options => { options.UseSqlite(config.DbConnString); });
}
    break;
case "postgres": {
    services.AddDbContext<MyDb>(options => options.UseNpgsql(config.DbConnString));
    services.AddDbContext<NpgsqlMyDb>(options => options.UseNpgsql(config.DbConnString));
}
    break;
default: {
    throw new Exception($"DbProvider not recognized: {config.DbProvider}");
} } 

然后,在 Startup.Configure 中进行迁移:

void ProcessDb<T>()
where T : MyDb {
    using var db = services.GetService<T>();
    db.Database.Migrate();

    // ... perform other startup tasks with db }

switch (config.DbProvider.ToLower()) {
    case "sqlite": {
        ProcessDb<SqliteMyDb>();
        break;
    }
    case "postgres": {
        ProcessDb<NpgsqlMyDb>();
        break;
    }
    default: {
        throw new Exception();
    } } 

总之,对于每个额外的提供程序,添加一个子类,在 ConfigureServices 中添加一个两行案例,在 Configure 中添加一个案例。


推荐阅读