C# 实体框架迁移 - 启用自动迁移以及添加的迁移

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10646111/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-09 14:38:35  来源:igfitidea点击:

Entity Framework Migrations - Enable AutoMigrations along with added migration

c#asp.net-mvc-3entity-frameworkef-migrations

提问by jdavis

I'm utilizing Entity Framework 4.3 Migrations in my project. I would like to use Automatic migrations so that when I make modifications to my domain objects and my context class, my database automatically updates when I run the project. I have this working so far.

我在我的项目中使用 Entity Framework 4.3 Migrations。我想使用自动迁移,这样当我修改域对象和上下文类时,我的数据库会在我运行项目时自动更新。到目前为止我有这个工作。

I would also like to use some Added Migrations in addition to the automatic migrations, and I would like the application to automatically jump to the latest version (based on my added migrations) when I run the application.

除了自动迁移之外,我还想使用一些添加的迁移,并且我希望应用程序在运行应用程序时自动跳转到最新版本(基于我添加的迁移)。

In order to do this I have placed this in the global.asax file...

为了做到这一点,我把它放在 global.asax 文件中......

Database.SetInitializer(new MigrateDatabaseToLatestVersion<MyContext, Core.Migrations.Configuration>());

Now this works, but when I do this it no longer automatically updates the database based on my domain objects.

现在这可行,但是当我这样做时,它不再根据我的域对象自动更新数据库。

I would like to be able to completely delete the database and then run the application and have all the automatic migrations run and then have my explicit migrations run and bring the database up to the latest version.

我希望能够完全删除数据库,然后运行应用程序并运行所有自动迁移,然后运行我的显式迁移并将数据库更新到最新版本。

I know I've had this working in a previous project, but I'm not sure what I'm doing wrong in this instance.

我知道我在之前的一个项目中做过这个,但我不确定在这个例子中我做错了什么。

Thanks

谢谢

采纳答案by Mirko

You need to pass a configuration that has the AutomaticMigrationsEnabled set to true in the constructor. Something like this should help:

您需要在构造函数中传递一个将 AutomaticMigrationsEnabled 设置为 true 的配置。这样的事情应该有帮助:


Database.SetInitializer(new MigrateDatabaseToLatestVersion<MyContext, MyConfiguration>());

with MyConfiguration being something like:

MyConfiguration 类似于:


public class MyConfiguration : Core.Migrations.Configuration
{
    public MyConfiguration { this.AutomaticMigrationsEnabled = true; }
}

DISCLAIMER: Just hacked this in, so small tweaks might be required to get this to compile

免责声明:刚刚破解了这个,所以可能需要做一些小的调整才能编译它

EDIT:

编辑:

Just checked with EF 4.3.1 and the code is like this for the initializer:

刚刚检查了 EF 4.3.1,初始化程序的代码是这样的:

Database.SetInitializer(new MigrateDatabaseToLatestVersion<DataContext, MyConfiguration>());

and this for the configuration class:

这对于配置类:

public class MyConfiguration : System.Data.Entity.Migrations.DbMigrationsConfiguration<DataContext>
{
    public MyConfiguration()
    {
        this.AutomaticMigrationsEnabled = true;
    }
}

回答by jdavis

Here is my current solution, which I'm not completely satisfied with.

这是我目前的解决方案,我并不完全满意。

protected void Application_Start()
{
    AreaRegistration.RegisterAllAreas();

    RegisterGlobalFilters(GlobalFilters.Filters);
    RegisterRoutes(RouteTable.Routes);

    var context = new KCSoccerDataContext();
    var initializeDomain = new CreateDatabaseIfNotExists<KCSoccerDataContext>();
    var initializeMigrations = new MigrateDatabaseToLatestVersion<KCSoccerDataContext, Core.Migrations.Configuration>();

    initializeDomain.InitializeDatabase(context);
    initializeMigrations.InitializeDatabase(context);

}

I'm actually creating two different initializers. The first, using CreateDatabaseIfNotExists, succcessfully goes through and creates tables based on my Domain objects. The second, using MigrateDatabaseToLatestVersion, executes all of my explicit migrations.

我实际上正在创建两个不同的初始化程序。第一个,使用 CreateDatabaseIfNotExists,成功地通过并基于我的域对象创建表。第二个,使用 MigrateDatabaseToLatestVersion,执行我所有的显式迁移。

I don't like it because Automatic Migrations are basically disabled. So in order to add or change my Domain model I have to completely drop the database and recreate it. This won't be acceptable once I've moved the application to production.

我不喜欢它,因为自动迁移基本上是禁用的。因此,为了添加或更改我的域模型,我必须完全删除数据库并重新创建它。一旦我将应用程序移至生产环境,这将是不可接受的。

回答by Roger

After banging my head on this for several hours, I finally came up with a solution that creates the database if necessary orupgrades it if out of date. We use this technique in Gallery Server Pro to make it easy to install the first time or upgrade previous versions.

经过几个小时的思考,我终于想出了一个解决方案,可以在必要时创建数据库,或者在过期时升级它。我们在 Gallery Server Pro 中使用这种技术,以便于首次安装或升级以前的版本。

private static void InitializeDataStore()
{
  System.Data.Entity.Database.SetInitializer(new System.Data.Entity.MigrateDatabaseToLatestVersion<GalleryDb, GalleryDbMigrationConfiguration>());

  var configuration = new GalleryDbMigrationConfiguration();
  var migrator = new System.Data.Entity.Migrations.DbMigrator(configuration);
  if (migrator.GetPendingMigrations().Any())
  {
    migrator.Update();
  }
}

public sealed class GalleryDbMigrationConfiguration : DbMigrationsConfiguration<GalleryDb>
{
  protected override void Seed(GalleryDb ctx)
  {
    MigrateController.ApplyDbUpdates();
  }
}

I wrote up a blog post with a few more details: Using Entity Framework Code First Migrations to auto-create and auto-update an application

我写了一篇包含更多细节的博客文章: 使用实体框架代码优先迁移来自动创建和自动更新应用程序

回答by Olamide James

If your application contains Startup.cs class, you can use DbMigrator Class as follows Go to your App_Start folder, open Startup.Auth Paste these lines of code inside of ConfigureAuth method

如果您的应用程序包含 Startup.cs 类,您可以使用 DbMigrator 类如下进入您的 App_Start 文件夹,打开 Startup.Auth 将这些代码行粘贴到 ConfigureAuth 方法中

var configuration = new Migrations.Configuration();
        var dbmigrator = new DbMigrator(configuration);
        dbmigrator.Update();

NOTE: Remember to use this namespace- using System.Data.Entity.Migrations;

注意:记住使用这个命名空间——使用 System.Data.Entity.Migrations;

what this does is to update your database to the latest version anytime the application starts up

这样做是在应用程序启动时将数据库更新到最新版本

回答by cibin

You just need to do

你只需要做

    private static void InitializeDataStore()
    {
        System.Data.Entity.Database.SetInitializer(new System.Data.Entity.MigrateDatabaseToLatestVersion<GalleryDb, GalleryDbMigrationConfiguration>());
        System.Data.Entity.Database.Initialize(false);
    }

回答by alhpe

Same solution that Roger did but using an static constructor on the DbContext. Full code below.... this allow the initialization code to live on the class itself and is self-invoked at the first instantiation of the DataDbContext class.

与 Roger 相同的解决方案,但在 DbContext 上使用了静态构造函数。下面的完整代码......这允许初始化代码存在于类本身上,并在 DataDbContext 类的第一次实例化时自调用。

public partial class DataDbContext : DbContext
{
    public DataDbContext()
        : base("name=DefaultConnection")
    {
    }

    static DataDbContext() // This is an enhancement to Roger's answer
    {
        Database.SetInitializer(new DataDbInitializer()); 

        var configuration = new DataDbConfiguration();
        var migrator = new DbMigrator(configuration);

        if (migrator.GetPendingMigrations().Any())
            migrator.Update();
    }

    // DbSet's
    public DbSet<CountryRegion> CountryRegion { get; set; }
    // bla bla bla.....

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
        modelBuilder.Conventions.Remove<ManyToManyCascadeDeleteConvention>();
        modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();

        Configuration.ProxyCreationEnabled = false;
        Configuration.LazyLoadingEnabled = false;
        //Configuration.ValidateOnSaveEnabled = false; 

        base.OnModelCreating(modelBuilder);

        modelBuilder.Configurations.AddFromAssembly(Assembly.GetExecutingAssembly()); // Discover and apply all EntityTypeConfiguration<TEntity> of this assembly, it will discover (*)
    }

}

internal sealed class DataDbInitializer : MigrateDatabaseToLatestVersion<DataDbContext, DataDbConfiguration>
{
}


internal sealed class DataDbConfiguration : DbMigrationsConfiguration<DataDbContext>
{
    public DataDbConfiguration()
    {
        AutomaticMigrationsEnabled = true;
        AutomaticMigrationDataLossAllowed = true;
    }

    protected override void Seed(DataDbContext context)
    {
        DataSeedInitializer.Seed(context); 
        base.Seed(context);
    }
}

internal static class DataSeedInitializer
{
    public static void Seed(DataDbContext context)
    {
        SeedCountryRegion.Seed(context);
        // bla bla bla.....

        context.SaveChanges();
    }
}

internal static class SeedCountryRegion
{
    public static void Seed(DataDbContext context)
    {
        context.CountryRegion.AddOrUpdate(countryRegion => countryRegion.Id,

            new CountryRegion { Id = "AF", Name = "Afghanistan" },
            new CountryRegion { Id = "AL", Name = "Albania" },
            // bla bla bla.....

            new CountryRegion { Id = "ZW", Name = "Zimbabwe" });

        context.SaveChanges();
    }
}

public class CountryRegionConfiguration : EntityTypeConfiguration<CountryRegion> // (*) Discovered by
{
    public CountryRegionConfiguration()
    {
        Property(e => e.Id)
            .IsRequired()
            .HasMaxLength(3);

        Property(e => e.Name)
            .IsRequired()
            .HasMaxLength(50);
    }
}

public partial class CountryRegion : IEntity<string>
{
    // Primary key 
    public string Id { get; set; }

    public string Name { get; set; }

}

public abstract class Entity<T> : IEntity<T>
{
    //Primary key
    public abstract T Id { get; set; }
}

public interface IEntity<T>
{
    T Id { get; set; }
}

We can see that the Seed method is running again and again.. We can avoid this by checking if a migration already exits, since one is applied automatically when the database is create.. then we can refactor the DataDbConfiguration as follows...

我们可以看到 Seed 方法一次又一次地运行.. 我们可以通过检查迁移是否已经存在来避免这种情况,因为在创建数据库时会自动应用迁移.. 然后我们可以如下重构 DataDbConfiguration...

internal sealed class DataDbConfiguration : DbMigrationsConfiguration<DataDbContext>
{
    private readonly bool _isInitialized;

    public DataDbConfiguration()
    {
        AutomaticMigrationsEnabled = true;
        AutomaticMigrationDataLossAllowed = true;

        var migrator = new DbMigrator(this);

        _isInitialized = migrator.GetDatabaseMigrations().Any();
    }

    protected override void Seed(DataDbContext context)
    {
        InitializeDatabase(context);
    }

    public void InitializeDatabase(DataDbContext context)
    {

        if (!_isInitialized)
        {
            if (context.Database.Connection.ConnectionString.Contains("localdb"))
            {
                DataSeedInitializer.Seed(context); // Seed Initial Test Data
            }
            else
            {
                // Do Seed Initial Production Data here
            }

        }
        else
        {
            // Do any recurrent Seed here
        }
    }
}