Manually Provide DbContext to DbMigrator

2019-03-29 09:58发布

问题:

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?

回答1:

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