Entity Framework,自动应用迁移

Entity Framework, Automatic apply Migrations

我正在使用 Entity Framework Code First 方法 AutomaticMigrationsEnabled = true:

Database.SetInitializer(new MigrateDatabaseToLatestVersion<DbContext, MigrateDBConfiguration>());
//////////////////////////////////

public class MigrateDBConfiguration : System.Data.Entity.Migrations.DbMigrationsConfiguration<DbContext>
{
    public MigrateDBConfiguration()
    {
        AutomaticMigrationsEnabled = true;
        AutomaticMigrationDataLossAllowed = true;
    }
}

项目的第一个 运行 按预期创建了数据库和表。通过添加或删除字段更改我的模型后,我 运行 Add-Migration。迁移 class 已生成,但在 运行 项目后出现此异常:

An exception of type 'System.InvalidOperationException' occurred in EntityFramework.dll but was not handled in user code

Additional information: The model backing the 'DBContext' context has changed since the database was created.

编辑: 根据 arturo menchaca 答案中的指导,我这样更改了我的代码:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        Database.SetInitializer(new MigrateDatabaseToLatestVersion<DBContext, MigrateDBConfiguration<DBContext>>());

...

更改后出现此异常:

There is already an object named 'MyTable' in the database.

如何应用我的数据库迁移?

Automatic Migrations 意味着您不需要 运行 add-migration 命令来更改模型,但您必须 运行 update-database 手动命令。

如果在您调用 update-database 时启用了 自动迁移 ,如果您的模型中有待处理的更改,将添加 'automatic' 迁移和数据库会更新的。

如果您希望更新数据库而不需要调用 update-database 命令,您可以在上下文的 OnModelCreating() 方法中添加 Database.SetInitializer(...),如下所示:

public class MyContext : DbContext
{
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        Database.SetInitializer(new MigrateDatabaseToLatestVersion<MyContext, MigrateDBConfiguration>());
    }

    ...
}

public class MigrateDBConfiguration : System.Data.Entity.Migrations.DbMigrationsConfiguration<MyContext>
{
    ...

请注意,您应该使用真实上下文声明 DbMigrationsConfigurationMigrateDatabaseToLatestVersion,而不是默认的 DbContext

终于,我找到了解决问题的办法。我在每个应用程序启动时调用此方法:

public void InitializeDatabase(DataAccessManager context)
{
    if (!context.Database.Exists() || !context.Database.CompatibleWithModel(false))
    {
        var configuration = new DbMigrationsConfiguration();
        var migrator = new DbMigrator(configuration);
        migrator.Configuration.TargetDatabase = new DbConnectionInfo(context.Database.Connection.ConnectionString, "System.Data.SqlClient");
        var migrations = migrator.GetPendingMigrations();
        if (migrations.Any())
        {
            var scriptor = new MigratorScriptingDecorator(migrator);
            var script = scriptor.ScriptUpdate(null, migrations.Last());

            if (!string.IsNullOrEmpty(script))
            {
                context.Database.ExecuteSqlCommand(script);
            }
        }
    }
}

如果您的实体有变化,您需要先 运行 add-migration 创建迁移脚本。

之后在你的 Global.asax

你需要这样的代码

        var configuration = new MyProject.Configuration();
        var migrator = new System.Data.Entity.Migrations.DbMigrator(configuration);            

        migrator.Update();

每次您 运行 您的 asp.net 项目时,它会自动检查您是否有新的迁移到 运行 和 运行 update-database你.

Microsoft 在运行时处理迁移,here

例如,您可以在 Program.cs 中执行此操作:(已在 .NET 5.0 预览版中测试)

public static void Main(string[] args)
{
    var host = CreateHostBuilder(args).Build();

    MigrateDatabase(host);

    host.Run();
}

private static void MigrateDatabase(IHost host)
{
    using var scope = host.Services.CreateScope();
    var services = scope.ServiceProvider;

    try
    {
        var context = services.GetRequiredService<ApplicationDbContext>();
        context.Database.Migrate();
    }
    catch (Exception ex)
    {
        var logger = services.GetRequiredService<ILogger<Program>>();
        logger.LogError(ex, "An error occurred creating the DB.");
    }
}

使用Microsoft.EntityFrameworkCore;

        await _dbContext.Database.MigrateAsync();
        _dbContext.Database.Migrate();

        await _dbContext.Database.EnsureCreatedAsync();
         _dbContext.Database.EnsureCreated();

这两种方法都检查数据库是否存在,如果不存在,他们都创建它。

  • Migrate() 使用迁移,适用于迁移或关系数据库。
  • EnsureCreated() 不使用迁移,这意味着一旦使用此方法创建了数据库,就无法对其执行进一步的迁移。