When I create a context with a default connection string (as read from the app.config
) the database is created and the migrations work - basically everything is in order. Whereas when the connection string is created programatically (using SqlConnectionStringBuilder
):
A
);CreateDbIfNotExists()
creates the newest version of database model but the migration mechanisms are not invoked (scenario B
).In A
an exception is thrown when I wish to access the database, as - obviously - it isn't there. In B
database is created properly migration mechanisms are not called, as is the case in standard connection string.
app.config: "Data Source=localhost\\SQLEXPRESS;Initial Catalog=Db13;User ID=xxx;Password=xxx
"
builder:
sqlBuilder.DataSource = x.DbHost; sqlBuilder.InitialCatalog = x.DbName; sqlBuilder.UserID = x.DbUser; sqlBuilder.Password = x.DbPassword;
initializer:
Database.SetInitializer( new MigrateDatabaseToLatestVersion< MyContext, Migrations.Configuration >() );
Specs: Entity Framework: 5.0, DB: SQL Server Express 2008
Go to Package Manager Console and type command help migration. Type Enable-Migrations -ContextTypeName EXPShopContext. This command creates a migration folder with InitialCreate.
If you want to change the connection string go to the app. config and remove all the connection strings. Now go to the edmx, right click on the designer surface, select Update model from database, choose the connection string from the dropdown, Click next, Add or Refresh (select what you want) and finish.
If your migration does not work correctly try to set Database.Initialize(true)
in DbContext ctor.
public CustomContext(DbConnection connection) : base(connection, true) { Database.Initialize(true); }
I have similar problem with migrations. And in my solution I have to always set database initializer in ctor, like below
public CustomContext(DbConnection connection) : base(connection, true) { Database.SetInitializer(new CustomInitializer()); Database.Initialize(true); }
In custom initializer you have to implement InitalizeDatabase(CustomContex context)
method, eg.
class CustomInitializer : IDatabaseInitializer<CustomContext> { public void InitializeDatabase(CustomContext context) { if (!context.Database.Exists || !context.Database.CompatibleWithModel(false)) { var configuration = new Configuration(); var migrator = new DbMigrator(configuration); migrator.Configuration.TargetDatabase = new DbConnectionInfo(context.Database.Connection.ConnectionString, "System.Data.SqlClient"); var migrations = migrator.GetPendingMigrations(); if (migrations.Any()) { var scriptor = new MigratorScriptingDecorator(migrator); string script = scriptor.ScriptUpdate(null, migrations.Last()); if (!String.IsNullOrEmpty(script)) { context.Database.ExecuteSqlCommand(script); } } } } }
UPDATED
He is a solution, with NO Connection strings in app.config. Uses automatic migrations and 2 databases using the same context. The real runtime supplied Connection. Approach.
APP.CONFIG (Uses EF 6)
<?xml version="1.0" encoding="utf-8"?> <configuration> <configSections> <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" /> </configSections> <startup> <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" /> </startup> <entityFramework> <defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework"> <parameters> <parameter value="Data Source=localhost; Integrated Security=True; MultipleActiveResultSets=True" /> </parameters> </defaultConnectionFactory> </entityFramework> </configuration>
I rewrote the code to make as small as possible for Demo:
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) { Database.SetInitializer(new MigrateDatabaseToLatestVersion<Ef6Ctx, Ef6MigConf>()); WhichDb.DbName = "HACKDB1"; var sqlConn = GetSqlConn4DBName(WhichDb.DbName); var context = new Ef6Ctx(sqlConn); context.Database.Initialize(true); AddJunk(context); //sqlConn.Close(); //?? whatever other considerations, dispose of context etc... Database.SetInitializer(new MigrateDatabaseToLatestVersion<Ef6Ctx, Ef6MigConf>()); // yes its default again reset this !!!! WhichDb.DbName = "HACKDB2"; var sqlConn2 = GetSqlConn4DBName(WhichDb.DbName); var context2 = new Ef6Ctx(sqlConn2); context2.Database.Initialize(true); AddJunk(context2); } public static class WhichDb { // used during migration to know which connection to build public static string DbName { get; set; } } 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() { var sqlConn = Program.GetSqlConn4DBName(Program.WhichDb.DbName); // NASTY but it works return new Ef6Ctx(sqlConn); } } public class Ef6MigConf : DbMigrationsConfiguration<Ef6Ctx> { public Ef6MigConf() { 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 class Ef6Ctx : DbContext { public DbSet<pocotest> poco1s { get; set; } public Ef6Ctx(DbConnection dbConn) : base(dbConn, true) { } } }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With