Entity Framework Migrations - включить автоматическое перемещение вместе с добавлением миграции
Я использую Entity Framework 4.3 Миграции в моем проекте. Я хотел бы использовать автоматические миграции, чтобы при изменении моих объектов домена и моего класса контекста моя база данных автоматически обновлялась при запуске проекта. Я работаю до сих пор.
Я также хотел бы использовать некоторые Добавленные Миграции в дополнение к автоматическим переходам, и я хотел бы, чтобы приложение автоматически переходило к последней версии (основанной на моих добавленных миграциях) при запуске приложения.
Чтобы сделать это, я поместил это в файл global.asax...
Database.SetInitializer(new MigrateDatabaseToLatestVersion<MyContext, Core.Migrations.Configuration>());
Теперь это работает, но когда я это делаю, он больше не автоматически обновляет базу данных на основе моих объектов домена.
Я хотел бы иметь возможность полностью удалить базу данных, а затем запустить приложение и запустить все автоматические миграции, а затем выполнить мои явные миграции и довести базу данных до последней версии.
Я знаю, что у меня это работало в предыдущем проекте, но я не уверен, что я делаю неправильно в этом случае.
благодаря
Ответы
Ответ 1
Вам нужно передать конфигурацию с параметром 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;
}
}
Ответ 2
После нескольких ударов головой об этом, я наконец придумал решение, которое создает базу данных, если это необходимо, или обновляет ее, если она устарела. Мы используем этот метод в 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 для автоматического создания и автоматического обновления приложения
Ответ 3
Вот мое текущее решение, которое я не вполне доволен.
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, выполняет все мои явные миграции.
Мне это не нравится, потому что автоматическая миграция в основном отключена. Поэтому, чтобы добавить или изменить мою модель домена, я должен полностью отказаться от базы данных и воссоздать ее. Это будет неприемлемо, если я переведу приложение на производство.
Ответ 4
Вам просто нужно сделать
private static void InitializeDataStore()
{
System.Data.Entity.Database.SetInitializer(new System.Data.Entity.MigrateDatabaseToLatestVersion<GalleryDb, GalleryDbMigrationConfiguration>());
System.Data.Entity.Database.Initialize(false);
}
Ответ 5
Если ваше приложение содержит класс Startup.cs, вы можете использовать класс DbMigrator следующим образом. Перейдите в свою папку App_Start, откройте Startup.Auth. Вставьте эти строки кода внутри метода ConfigureAuth
var configuration = new Migrations.Configuration();
var dbmigrator = new DbMigrator(configuration);
dbmigrator.Update();
ПРИМЕЧАНИЕ. Не забудьте использовать этот namespace-, используя System.Data.Entity.Migrations;
это делается для обновления базы данных до последней версии в любое время, когда приложение запускается
Ответ 6
Такое же решение, которое сделал Роджер, но используя статический конструктор в DbContext. Полный код ниже.... это позволяет коду инициализации жить в самом классе и самозапускается при первом экземпляре класса DataDbContext.
public partial class DataDbContext : DbContext
{
public DataDbContext()
: base("name=DefaultConnection")
{
}
static DataDbContext() // This is an enhancement to Roger 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
}
}
}