Entity Framework Migrations - Enable AutoMigrations along with added migration

后端 未结 6 1584
青春惊慌失措
青春惊慌失措 2021-02-04 09:34

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 cla

相关标签:
6条回答
  • 2021-02-04 09:50

    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.

    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.

    0 讨论(0)
  • 2021-02-04 09:53

    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);
        }
    
    0 讨论(0)
  • 2021-02-04 09:56

    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

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

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

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

    0 讨论(0)
  • 2021-02-04 10:08

    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.

    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...

    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
            }
        }
    }
    
    0 讨论(0)
  • 2021-02-04 10:10

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

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

    with MyConfiguration being something like:

    
    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:

    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;
        }
    }
    
    0 讨论(0)
  • 2021-02-04 10:12

    After banging my head on this for several hours, I finally came up with a solution that creates the database if necessary or upgrades 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.

    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

    0 讨论(0)
提交回复
热议问题