Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

EntityFramework code-first custom connection string and migrations

Tags:

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):

  • database isn't created when the database is not present (scenario 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

like image 681
Red XIII Avatar asked Mar 19 '13 16:03

Red XIII


People also ask

How do you add-migration in code first approach?

Go to Package Manager Console and type command help migration. Type Enable-Migrations -ContextTypeName EXPShopContext. This command creates a migration folder with InitialCreate.

How do I change the connection string in EDMX?

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.


2 Answers

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

like image 77
rraszewski Avatar answered Sep 23 '22 21:09

rraszewski


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) { } } } 
like image 35
phil soady Avatar answered Sep 22 '22 21:09

phil soady