问题
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; }
}
}
来源:https://stackoverflow.com/questions/19868142/manually-provide-dbcontext-to-dbmigrator