Search code examples
c#entity-frameworkdbcontextentity-framework-migrationsdbmigrator

Manually Provide DbContext to DbMigrator


Platform .NET 4.5 and Entity Framework 6.

Question I have the following code to execute a Migration:

//The following function just returns an object of the Configuration() class 
//generated by code migrations
var migratorConfig = currentMigrationProvider.CreateDbMigrationConfiguration(); 
var dbMigrator = new System.Data.Entity.Migrations.DbMigrator(migratorConfig);
dbMigrator.Update();

The problem is that Update() function tries to create an instance of my DbContext class and for a few good reasons I need to manually create the context and feed it to dbMigrator. Is that possible? How?


Solution

  • Yes it is possible to control migrations and the context. This is important if you are managing the connection. The example shows connecting to 2 different Dbs. It is a little convoluted. So i built a little test project to demo how.

    using System;
    using System.Data.Common;
    using System.Data.Entity;
    using System.Data.Entity.Infrastructure;
    using System.Data.Entity.Migrations;
    
    namespace Ef6Test {
    public class Program {
        public static void Main(string[] args) {
            ExecDb1();
            ExecDB2();
           ExecDbCtx3();
        }
    
        private static void ExecDb1() {
            Database.SetInitializer(new MigrateDatabaseToLatestVersion<Ef6Ctx, Ef6MigConf>());
            WhichDb.DbName = "HACKDB1";
            WhichDb.ConnType = ConnType.CtxViaDbConn;
            var sqlConn = GetSqlConn4DBName(WhichDb.DbName);
            var context = new Ef6Ctx(sqlConn);
            context.Database.Initialize(true);
            Console.WriteLine(WhichDb.DbName, context.Database.Exists() );
            AddJunk(context);
            //sqlConn.Close();  //?? whatever other considerations, dispose of context etc...
        }
    
        private static void ExecDB2() {
            // yes other its default again reset this !!!!
            WhichDb.DbName = "HACKDB2";
            WhichDb.ConnType = ConnType.CtxViaDbConn;
            var sqlConn2 = GetSqlConn4DBName(WhichDb.DbName);
            var context2 = new Ef6Ctx2(sqlConn2);
            Console.WriteLine(context2.Database.Exists());
            Database.SetInitializer(new MigrateDatabaseToLatestVersion<Ef6Ctx2, Ef6MigConf2>());
            context2.Database.Initialize(true);
            Console.WriteLine(WhichDb.DbName, context2.Database.Exists());
            AddJunk(context2);
        }
    
        private static void ExecDbCtx3() {
            Database.SetInitializer(new MigrateDatabaseToLatestVersion<Ef6Ctx3, Ef6MigConf3>());
            // Database.SetInitializer(new CreateDatabaseIfNotExists<Ef6Ctx3>());
            // Database.SetInitializer(null);
            WhichDb.ConnectionName = "AppCfgName";
            WhichDb.ConnType = ConnType.CtxViaConnectionName;
    
            var context3 = new Ef6Ctx3(WhichDb.ConnectionName);
            context3.Database.Initialize(true);
            Console.WriteLine(WhichDb.ConnectionName, context3.Database.Exists());
            AddJunk(context3);
        }
    
    
        public static class WhichDb {
            public static string DbName { get; set; }
            public static string ConnectionName { get; set; }
            public static ConnType ConnType { get; set; }
        }
    
        public enum ConnType {
            CtxViaDbConn,
            CtxViaConnectionName
        }
    
        private static void AddJunk(DbContext context) {
            var poco = new pocotest();
            poco.f1 = DateTime.Now.ToString();
            //  poco.f2 = "Did somebody step on a duck?";  //comment in for second run
            context.Set<pocotest>().Add(poco);
            context.SaveChanges();
        }
    
        public static DbConnection GetSqlConn4DBName(string dbName) {
            var sqlConnFact = new SqlConnectionFactory(
                "Data Source=localhost; Integrated Security=True; MultipleActiveResultSets=True");
            var sqlConn = sqlConnFact.CreateConnection(dbName);
            return sqlConn;
        }
    }
    
    public class MigrationsContextFactory : IDbContextFactory<Ef6Ctx> {
        public Ef6Ctx Create() {
            switch (Program.WhichDb.ConnType) {
                case Program.ConnType.CtxViaDbConn:
                    var sqlConn = Program.GetSqlConn4DBName(Program.WhichDb.DbName); // NASTY but it works
                    return new Ef6Ctx(sqlConn);
    
                case Program.ConnType.CtxViaConnectionName:
                    return new Ef6Ctx(Program.WhichDb.ConnectionName);
                default:
                    throw new ArgumentOutOfRangeException();
            }
        }
    }
    
    public class MigrationsContextFactory2 : IDbContextFactory<Ef6Ctx2> {
        public Ef6Ctx2 Create() {
            switch (Program.WhichDb.ConnType) {
                case Program.ConnType.CtxViaDbConn:
                    var sqlConn = Program.GetSqlConn4DBName(Program.WhichDb.DbName); // NASTY but it works
                    return new Ef6Ctx2(sqlConn);
    
                case Program.ConnType.CtxViaConnectionName:
                    return new Ef6Ctx2(Program.WhichDb.ConnectionName);
                default:
                    throw new ArgumentOutOfRangeException();
            }
        }
    }
    
    public class MigrationsContextFactory3 : IDbContextFactory<Ef6Ctx3> {
        public Ef6Ctx3 Create() {
            switch (Program.WhichDb.ConnType) {
                case Program.ConnType.CtxViaDbConn:
                    var sqlConn = Program.GetSqlConn4DBName(Program.WhichDb.DbName); // NASTY but it works
                    return new Ef6Ctx3(sqlConn);
    
                case Program.ConnType.CtxViaConnectionName:
                    return new Ef6Ctx3(Program.WhichDb.ConnectionName);
                default:
                    throw new ArgumentOutOfRangeException();
            }
        }
     }
    
    public class Ef6MigConf : DbMigrationsConfiguration<Ef6Ctx> {
        public Ef6MigConf() {
            AutomaticMigrationsEnabled = true;
            AutomaticMigrationDataLossAllowed = true;
        }
     }
    
    public class Ef6MigConf2 : DbMigrationsConfiguration<Ef6Ctx2> {
        public Ef6MigConf2() {
            AutomaticMigrationsEnabled = true;
            AutomaticMigrationDataLossAllowed = true;
        }
     }
    
     public class Ef6MigConf3 : DbMigrationsConfiguration<Ef6Ctx3> {
        public Ef6MigConf3() {
            AutomaticMigrationsEnabled = true;
            AutomaticMigrationDataLossAllowed = true;
        }
    }
    
    public class pocotest {
        public int Id { get; set; }
        public string f1 { get; set; }
     public string f2 { get; set; } // comment in for second run
     public string f2a { get; set; } // comment in for second run
      public string f3 { get; set; } // comment in for second run
     public string f5 { get; set; } // comment in for second run
     public string f6b { get; set; } // comment in for second run
    }
    
    public class Ef6Ctx : DbContext {
        public Ef6Ctx(DbConnection dbConn) : base(dbConn, true) { }
    
        public Ef6Ctx(string connectionName) : base(connectionName) { }
    
        public DbSet<pocotest> poco1s { get; set; }
    }
    
    public class Ef6Ctx2 : DbContext {
        public Ef6Ctx2(DbConnection dbConn) : base(dbConn, true) { }
        public Ef6Ctx2(string connectionName) : base(connectionName) { }
        public DbSet<pocotest> poco1s { get; set; }
    }
    }