Search code examples
asp.net-mvc-4visual-studio-2017ef-code-firstentity-framework-migrations

Code First Migration Problem in Data Layer


I have an existing ASP.NET MVC 4 web app where all code files resides in one project:

  • Satinge (.NET Framework MVC 4 web application project)

I am now reorganizing the app into presentation, data and services layers:

  • Satinge (.NET Framework MVC 4 web application - presentation layer project)
  • Satinge.Data (.NET Framework class library - data layer project)
  • Satinge.Services (.NET Framework class library - services layer project)

I have moved all data models and migration files to the data layer and so far the app builds fine and works when I try running it in debug mode. However, when I try adding a new model it won't let me run Add-Migration command in the Package Manager Console (Default Project: Satinge.Data). I am getting the following error:

Unable to generate an explicit migration because the following explicit migrations are pending: [--list of all migrations--]. Apply the pending explicit migrations before attempting to generate a new explicit migration.

It wants me to apply migrations that has already been applied to the database.

When I try running Update-Database, I get an error saying:

There is already an object named 'Name of Existing Table' in the database.


Solution

  • I'll assume you work with EF6 as EF Core uses different table layout (and does not include namespaces in the DB so you'd probably not have this issue in the first place).

    As EF needs to track your actual DB state for migrations, it uses a special table called __MigrationHistory (which can be renamed if need be). Since your migrations are good ol' C# classes - the engine needs to then somehow figure out which of these got applied already. EF developers chose to opt for fully qualified class names. This is exactly what ContextKey column on that table is for.

    So ultimately you have two choices - either update the table or define custom DbConfiguration to use different namespace:

    public class MyDbConfiguration: DbConfiguration
    {
        public MyDbConfiguration()
        {
            AutomaticMigrationsEnabled = false;
            ContextKey = "Old.Migrations.Namespace";
        }
    }
    ...
    [DbConfigurationType("MyNamespace.MyDbConfiguration, MyAssembly")] // there are few ways to plug it in: https://learn.microsoft.com/en-us/ef/ef6/fundamentals/configuring/code-based
    public class MyContextContext : DbContext
    {
       ...
    }