Вопрос по asp.net-mvc-3, c#, entity-framework – Миграции Entity Framework - включите автоматическую миграцию вместе с добавленной миграцией

11

Я использую Entity Framework 4.3 Миграции в моем проекте. Я хотел бы использовать автоматические миграции, чтобы при внесении изменений в мои доменные объекты и мой контекстный класс моя база данных автоматически обновлялась при запуске проекта. У меня это работает до сих пор.

Я также хотел бы использовать некоторые добавленные миграции в дополнение к автоматическим миграциям, и я хотел бы, чтобы приложение автоматически переходило на последнюю версию (на основе моих добавленных миграций) при запуске приложения.

Для этого я поместил это в файл global.asax ...

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

Теперь это работает, но когда я делаю это, он больше не обновляет базу данных автоматически на основе моих доменных объектов.

Я хотел бы иметь возможность полностью удалить базу данных, а затем запустить приложение и запустить все автоматические миграции, а затем запустить мои явные миграции и привести базу данных к последней версии.

Я знаю, что у меня это работало в предыдущем проекте, но я не уверен, что я делаю неправильно в этом случае.

Спасибо

Ваш Ответ

6   ответов
0

что и у Роджера, но с использованием статического конструктора в 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
        }
    }
}
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, успешно проходит и создает таблицы на основе моих объектов Domain. Второй, использующий MigrateDatabaseToLatestVersion, выполняет все мои явные миграции.

Мне это не нравится, потому что автоматические миграции в основном отключены. Поэтому, чтобы добавить или изменить модель моего домена, я должен полностью удалить базу данных и воссоздать ее. Это не будет приемлемо после того, как я переместил приложение в производство.

10

в которой для AutomaticMigrationsEnabled установлено значение true в конструкторе. Примерно так должно помочь:


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

с MyConfiguration примерно так:


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

ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ: Просто взломали это, поэтому могут потребоваться небольшие изменения, чтобы заставить это скомпилировать

EDIT:

Только что проверил с EF 4.3.1 и код для инициализатора выглядит так:

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

и это для класса конфигурации:

public class MyConfiguration : System.Data.Entity.Migrations.DbMigrationsConfiguration<DataContext>
{
    public MyConfiguration()
    {
        this.AutomaticMigrationsEnabled = true;
    }
}
Это так работает. Мне нужно было добавитьAutomaticMigrationDataLossAllowed = true; для некоторых миграций. Это не безопасный способ жить
К сожалению, у меня уже есть все это на месте. К сожалению, потому что я уже делаю это, и это не работает. jdavis
то же самое здесь, и это абсолютно ничего не делает. Если я добавлю новое свойство в класс модели, оно не будет добавлено в соответствующую таблицу.
7

которое создает базу данных при необходимости.or обновляет его, если устарел. Мы используем эту технику в 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();
  }
}

Я написал сообщение в блоге с несколькими дополнительными деталями: Использование Entity Framework Code First Migrations для автоматического создания и автоматического обновления приложения

Что такоеMigrateController ?
обновленная ссылка:galleryserverpro.blogspot.ca/2013/10/…
MigrateController - это пользовательский класс, который вставляет начальные данные, если таблицы пусты, и обрабатывает любые необходимые изменения схемы / данных. Посмотрите пример, посмотрев исходный код Gallery Server. Вы можете скачать его по адресуgalleryserverpro.com/release-history (найдите на странице исходный код, и вы увидите ссылку, чтобы получить исходный код 3.2.1).
то, что мы могли бы сделать, это иметь статический конструктор в dbcontext
System.Data.Entity.Migrations.DbMigrator было именно то, что я искал. Нет необходимости запускать команду в NuGet PMC. Просто в C #, как при развертывании новой версии в любом месте, кроме вашей dev-машины.
0

вы можете использовать класс 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;

что это делает, чтобы обновить вашу базу данных до последней версии в любое время при запуске приложения

1

    private static void InitializeDataStore()
    {
        System.Data.Entity.Database.SetInitializer(new System.Data.Entity.MigrateDatabaseToLatestVersion<GalleryDb, GalleryDbMigrationConfiguration>());
        System.Data.Entity.Database.Initialize(false);
    }
Я не вижу, как это отвечает на вопрос.

Похожие вопросы