13

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

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

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

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

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

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

我知道我在以前的项目中已经完成了这项工作,但我不确定在这种情况下我做错了什么。

谢谢

4

6 回答 6

12

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


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

MyConfiguration 类似于:


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

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

编辑:

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

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

这对于配置类:

public class MyConfiguration : System.Data.Entity.Migrations.DbMigrationsConfiguration<DataContext>
{
    public MyConfiguration()
    {
        this.AutomaticMigrationsEnabled = true;
    }
}
于 2012-05-18T11:31:31.933 回答
7

经过几个小时的努力,我终于想出了一个解决方案,可以在必要时创建数据库,或者在过时时对其进行升级。我们在 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();
  }
}

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

于 2013-10-21T20:39:00.170 回答
2

与 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; }
}

我们可以看到 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
        }
    }
}
于 2018-02-02T00:30:47.807 回答
1

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

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);

}

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

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

于 2012-05-19T14:51:19.673 回答
0

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

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

注意:请记住使用此命名空间 - using System.Data.Entity.Migrations;

它的作用是在应用程序启动时将数据库更新到最新版本

于 2017-04-07T07:46:50.640 回答
-1

你只需要做

    private static void InitializeDataStore()
    {
        System.Data.Entity.Database.SetInitializer(new System.Data.Entity.MigrateDatabaseToLatestVersion<GalleryDb, GalleryDbMigrationConfiguration>());
        System.Data.Entity.Database.Initialize(false);
    }
于 2017-07-06T19:42:35.380 回答