EF 6 tries to change unexisting table on Add-Migration / Update-Database - entity-framework-6

I'm doing the command :
PM> Add-Migration test
and here is generated migration:
`
public partial class test : DbMigration
{
public override void Up()
{
MoveTable(name: "dbo.AccountToken", newSchema: "cns");
...
but the issue I don't have AccountToken table anywhere (checked with: Select * from sys.tables where name like '%account%' )
The error is: 'Cannot find the object 'AccountToken', because it does not exist or you do not have permission.'
Thanx in advance

Related

How do I specify the name of a joiner table in an EF many to many relationship?

I am using EF Code First 6.2 With Dev Express XAF
In DevExpress.Persistent.BaseImpl.EF the Event class has a many to many relationship with the Resource class.
If I make a new project using the Dev Express Wizard with Code First then the joiner table will be called ResourceEvents
However somehow in some migration my joiner table got renamed to be EventResources.
How do I set it back to what it should be?
I tried adding the following to the DBContext
modelBuilder.Entity<Event>().HasMany(x => x.Resources).WithMany(x => x.Events)
.Map(
x =>
{
x.MapLeftKey("Event_ID");
x.MapRightKey("Resource_Key");
x.ToTable("ResourceEvents");
});
this causes a migration to want to create
public partial class ev : DbMigration
{
public override void Up()
{
DropPrimaryKey("dbo.ResourceEvents");
AddPrimaryKey("dbo.ResourceEvents", new[] { "Event_ID", "Resource_Key" });
}
public override void Down()
{
DropPrimaryKey("dbo.ResourceEvents");
AddPrimaryKey("dbo.ResourceEvents", new[] { "Resource_Key", "Event_ID" });
}
}
Running the migration causes an error
Cannot find the object "dbo.ResourceEvents" because it does not exist or you do not have permissions.
The trick was to add code to the migration to rename the table
RenameTable(name: "dbo.EventResources", newName: "ResourceEvents");
Having the fluent API seems important in letting EF know what the name of the table should be.

Enity Framework 6.0.0.0 : Unable to generate an explicit migration... with Code-based migration

The situation is :
Per tenant db.
Non-automatic Code-based based migration. The initial creation of the dbs is through Code First too. There are no preexisting dbs in the current scenario.
The exact db is not known during the generation of migration script becase there are many. The only thing I have is code - the Initial migration script based on the model in the beginning and the model with some modifications.
Existing dbs generated with initial script - everything works fine. Here is how I reproduce the problem :
Run PS command : Add-Migration -Name Initial -StartUpProjectName MyApp.Web -ProjectName MyApp.Migrations -ConfigurationTypeName "MyApp.Migrations.MyMigrationConfiguration" -ConnectionString "Data Source=.\SQLEXPRESS;Database=demo-db;Trusted_Connection=False;User ID=x;Password=x" -ConnectionProviderName "System.Data.SqlClient" - Works Fine
Run the app and the db is created. Stop the app. Make modification to the model.
Run PS command : Add-Migration -Name MySecondMigration -StartUpProjectName MyApp.Web -ProjectName MyApp.Migrations -ConfigurationTypeName "MyApp.Migrations.MyMigrationConfiguration" -ConnectionString "Data Source=.\SQLEXPRESS;Database=demo-db;Trusted_Connection=False;User ID=x;Password=x" -ConnectionProviderName "System.Data.SqlClient" - Boom.
Subtlety - The migrator does not even connect to MSSQL to check if the db even exists or has dbo.__MigrationHistory! I have goen further and turned off the MSSQL service! - It does not matter if I enter false db name or not or I turn off the entire MSSQL server - the error is the same and no connection is made. So how does it know a migration is pending when it does not check the database? I assume a bug.
I have __dbo.MigrationHistory created already with the Initial migration in it.
Error : Unable to generate an explicit migration because the following explicit migrations are pending: [201402121953301_Initial]. Apply the pending explicit migrations before attempting to generate a new explicit migration.
Here is my Configuration - nothing special :
public class MyMigrationConfiguration : DbMigrationsConfiguration<MyMigrationContext>
{
public MyMigrationConfiguration()
{
AutomaticMigrationsEnabled = false;
AutomaticMigrationDataLossAllowed = false;
MigrationsNamespace = "---";
MigrationsDirectory = "---";
}
}
Here is the method with wich I create the dbs :
public void CreateOrUpdateDb(string DbName)
{
try
{
string connectionString = _connectionStringProvider.GetConnectionString(DbName);
DbMigrationsConfiguration cfg = CreateMigrationsConfig(connectionString);
cfg.AutomaticMigrationsEnabled = false;
cfg.AutomaticMigrationDataLossAllowed = false;
DbMigrator dbMigrator = new DbMigrator(cfg);
dbMigrator.Update();
}
catch (MigrationsException exception)
{
_logger.Error(string.Format("Error creating database '{0}'",DbName), exception);
}
}
I have already searched and read whatever I can find on the web but most examples include the standart Configuration.cs and the like. Nobody explains why should I run Enable-Migrations because it creates Configuration.cs but I provide the Configuration class myself and do not need this other class.
Here is the exception stack :
> System.Data.Entity.Migrations.Infrastructure.MigrationsPendingException: Unable to generate an explicit migration because the following explicit migrations are pending: [201402121953301_Initial]. Apply the pending explicit migrations before attempting to generate a new explicit migration.
at System.Data.Entity.Migrations.DbMigrator.Scaffold(String migrationName, String namespace, Boolean ignoreChanges)
at System.Data.Entity.Migrations.Design.MigrationScaffolder.Scaffold(String migrationName, Boolean ignoreChanges)
at System.Data.Entity.Migrations.Design.ToolingFacade.ScaffoldRunner.Scaffold(MigrationScaffolder scaffolder)
at System.Data.Entity.Migrations.Design.ToolingFacade.ScaffoldRunner.Run()
at System.AppDomain.DoCallBack(CrossAppDomainDelegate callBackDelegate)
at System.AppDomain.DoCallBack(CrossAppDomainDelegate callBackDelegate)
at System.Data.Entity.Migrations.Design.ToolingFacade.Run(BaseRunner runner)
at System.Data.Entity.Migrations.Design.ToolingFacade.Scaffold(String migrationName, String language, String rootNamespace, Boolean ignoreChanges)
at System.Data.Entity.Migrations.AddMigrationCommand.Execute(String name, Boolean force, Boolean ignoreChanges)
at System.Data.Entity.Migrations.AddMigrationCommand.<>c__DisplayClass2.<.ctor>b__0()
Is there any way to force the migrator to make the script without telling me that there are some pending migrations even though there are not? This is 100% bug in EF but I do not know how to get around it.
We have found the answer - a smart colleague of mine and with the help of Reflector.
Inside EntityFramework.dll there is the class
System.Data.Entity.Migrations.DbMigrator with a method
Scaffold(string migrationName, string #namespace, bool ignoreChanges)
Which makes a call this.GetPendingMigrations
Which method calls another method on another class HistoryRepository.CreateHistoryQuery(HistoryContext context, string contextKey = null) with the parameter contextKey == NULL
But there inside this method this happens
contextKey = !string.IsNullOrWhiteSpace(contextKey) ? contextKey.RestrictTo(this._contextKeyMaxLength) : this._contextKey;
and the contextKey is not null anymore. IT actually becomes the type(YourInheritedDbMigrationConfiguration).ToString()
Where is the problem? The problem lies in the fact that
I use two different DbMigrationConfiguration classes
because the migration assembly is separated from the core of the application which makes
them two differently 'fully qualified named classes' which at the end
result in two different ContextKeys in the dbo._MigrationHistory table for the DbMigrationConfiguration which is used for the generation of the migration script.
So when I make the initial migration script and start the site and the site applies the script it is ok but in the dbo._MigrationHistory the ContextKey is "MyDbConigClass1". After that when I try Add-Migration which uses another DbMigrationConfiguration class the ContextKeys does not match - BOOM!
The solution : Added the same ContextKey = "MyTenantDb" in both of my configuration classes and everything started to work again because the type names no longer got involved but the DbMigrator used my custom ContextKey :)

ASP.NET Entity Framework Code First Migrarion

This a ASP.NET MVC with Entity Framework 6.1 Code First application.
I need my application to CREATE the database if it doesn't exists and seed the tables with some data. Also I need to Migrate the database on application start if the model has changed using MigrateDatabaseToLatestVersion.
On the Application_Start i have:
protected void Application_Start()
{
Database.SetInitializer(new MyAppDataInitializer());
Database.SetInitializer(new MigrateDatabaseToLatestVersion<MyAppDataContext, MyApp.Model.Migrations.Configuration>());
}
The initializer:
public class MyAppDataInitializer: CreateDatabaseIfNotExists<MyAppDataContext>
{
protected override void Seed(MyAppDataContext context)
{
Code to add some "CREATION DATA"
}
}
Here is the Migration Configuration class:
public class Configuration : DbMigrationsConfiguration<MyApp.Model.DataContext.MyAppDataContext>
{
public Configuration()
{
AutomaticMigrationsEnabled = true;
AutomaticMigrationDataLossAllowed = true;
ContextKey = "MyApp.Model.DataContext.MyAppDataContext";
}
protected override void Seed(MyApp.Model.DataContext.MyAppDataContext context)
{
Code to add some "MIGRATION DATA"
}
}
When my application starts it works as expected except for one thing:
If the database exists, it works perfect, it changes the database according to the new model and it seeds the database with the "MIGRATION DATA".
If the database doesn't exists it creates the database but it only seeds the database with the "MIGRATION DATA" but not with the "CREATION DATA". The SEED method on the inicializer is not called.
I'm sure there is something I'm doing wrong here, but I can't figure out how can I create the database when it doesn't exists and seed some "init" data that it only insert for the first time.
Then when changing the model it only changes the database and add the data I setup in the migration seed method in case I need it.
Could you help me with this?
Thanks in advance.
You're overwriting the initializer. It's a "set" not an "add" initializer and there can only be one..
protected void Application_Start()
{
Database.SetInitializer(new MyAppDataInitializer());
// Now the initializer gets "re-set" again and MyAppDataInitializer is not used at all
Database.SetInitializer(new MigrateDatabaseToLatestVersion<MyAppDataContext, MyApp.Model.Migrations.Configuration>());
}

Entity Framework - Code First - Multiple projects

I have one solution with three projects in it:
ToDo.Web
ToDo.Core
ToDo.Data
ToDo.Web is my startup project and is an MVC 4 solution.
ToDo.Core is a Class Library solution and it contains all my classes like User, Task etc.
ToDo.Data is my data repository and contains my ToDoContext model.
My ToDoModel model looks like this:
namespace ToDo.Data
{
public class ToDoModel : DbContext
{
public DbSet<Task> Tasks { get; set; }
public DbSet<User> Users { get; set; }
}
}
I am trying to get the project to create my database on my locally installed SQL Server 2012. So in my web.config (in the ToDo.Web project) I have the following connectionstring:
<add name="ToDo.Data.ToDoModel" connectionString="Data Source=XXX\YYY;Integrated Security=SSPI;initial catalog=ToDo" providerName="System.Data.SqlClient" />
I then try to execute the following command from Package Manager Console:
Enable-Migrations -projectname ToDo.Data -StartUpProjectName ToDo.Web
The command executes nicely with no errors. And I can see a Migrations folder in my ToDo.Data project. But it only contains a Configuration.cs file and no information about my model. And I cannot see the database being created on my SQL server either.
I have tried creating a simple Console application, using the same connection string where it works nicely.
I have tried adding the connection string to my app.config in the ToDo.Data project without luck.
Anyone who can guide me in the right direction?

Is there an object model for automating migrations?

Using EF migrations I wish to automate running a migration against an environment. I know I can do this via powershell call to Update-Database, but is there a way of doing this via the framework without having to launch an external process?
Yes, in your DbContext:
public static void SetInitializer()
{
Database.SetInitializer(new MigrateDatabaseToLatestVersion<DataContext, Configuration>());
}
Where Configuration is:
internal sealed class Configuration : DbMigrationsConfiguration<DataContext>
{
public Configuration()
{
AutomaticMigrationsEnabled = true;
}
}
You'll still need to release a Migration file for migrations that will make changes that will result in dataloss (unless you set AutomaticMigrationDataLossAllowed to true in the Configuration class - danger!) but you can make these files using the Add-Migration command in PMC.

Resources