none
What's the correct sequence of getting a database setup for Code-First migrations?

    Question

  • Here's what Ive been trying repeatedly for the past 6 hours - and which doesn't work.

    1) Installed the EF 4.3.1 package from NuGet in VS2010 SP1 (this was done weeks ago and has been working).

    2 Start with a "new" database that was created and initialized when the app started-up (using EF 4.3.1 Code First with Migrations enabled.   _MigrationHistory has an "Initial_Create" entry). At this point, the code and the database are in-sync.

    3 In VS2010, use EDM editor to make a trivial change to the code data model (add a new property to an existing entity), then rebuild the solution. The new property is in the generated code, and all looks OK.  I don't run the app at this point (it would get an error saying the database wasn't in-sync with the data model).

    4) Invoke add-migration command in PMC: add-migration AddTrivial -conf App -startup servicesproject -project servicesproject -verbose

    ("App" is the name of one of the four databases in my configuration.cs file).    

    5) Gets exception saying "The model backing the context has changed since the database was created".

    Did I miss a step?  Or is this a bug?

    BTW:  I don't know what I did differently, but I got the above to work ONCE in 6+ tries.

    DadCat

    Tuesday, July 03, 2012 7:30 PM

Answers

  • I was able to prevent the exception in add-migration command by changing my code to only invoke Database.SetInitializer when ModelContainer was being used by the application (or unit tests), and not invoke it when invoked by add-migration

    But it's not clear that I should continue to use DeleteDatabaseIfNotExists strategy when Migrations.  Should I use MigrateDatabaseToLatestVersion instead?

    But does that strategy work for explicity migrations?  Some of the docs seem to imply it's for automatic migrations.

    DadCat

    • Marked as answer by DadCat Friday, July 13, 2012 3:02 PM
    Thursday, July 05, 2012 10:10 PM

All replies

  • Hi DadCat,

    Welcome to MSDN Forum.

    Based on the post, I found you changed the model by EDM editor. Migrations are only support code first, where're you get the EDM editor?

    Best Regards


    Allen Li [MSFT]
    MSDN Community Support | Feedback to us

    Wednesday, July 04, 2012 8:01 AM
  • We are using a "hybrid" data modeling approach. We're using Code First, but we still use the EDM editor as a convenient way of visualizing and editing the data model. We then run a custom T4 tool to generate the changed model classes (we don't use the EDM to generate the database). It's simply a way to have the visual editing of the EDM editor but still use Code First. This has been working for many months, and I tend to forget that the EDM editor (as you correctly pointed-out) is not normally used by Code First...

    So forget that I mentioned using the EDM editor, and just assume that I modified our code class directly... here's the steps without using the EDM editor, but which still fail with the same exception...

    Background info:  There are four databases (DbContext's) in the app, named App, Catalog, Portfolio and Scheduler. They are all defined in the Services project. I could not use the enable-migrations command, since it doesn't handle multiple DbContext's. So I "enabled migrations" by creating a Migrations folder in the Services project and created my own Configuration.cs file (attached below).

    Here's the steps that fail... 

    1) Delete all databases and start app (without any data model changes).  Databases get created, an "InitialCreate" migration is added  to MigrationHistory in all four databases, and the app starts and works OK.  Then stop the app. 

    2) Manually add a new string property "Test" to an entity in the "Scheduler" code model  (instead of using the EDM editor and the T4 template):

       private string _test;
            [DisplayName("Test")]
            public string Test
            {
                get { return this._test; }
                set
                {
                    this._exclusiveGroup = value;
                    InvokePropertyChanged(new PropertyChangedEventArgs("Test"));
                }
            }

    (I chose the Scheduler database because it has only single entity).

    3) Rebuild solution, but don't start app (the code data model and database schema are no longer in-sync)

    4) Run add-migration command:

    PM> add-migration Scheduler_AddTest -conf Scheduler -project Services -startup Services -verbose

    5) Get exception:

    System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.InvalidOperationException: The model backing the 'ModelContainer' context has changed since the database was created. Consider using Code First Migrations to update the database (http://go.microsoft.com/fwlink/?LinkId=238269).

       at System.Data.Entity.CreateDatabaseIfNotExists`1.InitializeDatabase(TContext context)

       at System.Data.Entity.Database.<>c__DisplayClass2`1.<SetInitializerInternal>b__0(DbContext c)

       at System.Data.Entity.Internal.InternalContext.<>c__DisplayClass8.<PerformDatabaseInitialization>b__6()

       at System.Data.Entity.Internal.InternalContext.PerformInitializationAction(Action action)

       at System.Data.Entity.Internal.InternalContext.PerformDatabaseInitialization()

       at System.Data.Entity.Internal.LazyInternalContext.<InitializeDatabase>b__4(InternalContext c)

       at System.Data.Entity.Internal.RetryAction`1.PerformAction(TInput input)

       at System.Data.Entity.Internal.LazyInternalContext.InitializeDatabaseAction(Action`1 action)

       at System.Data.Entity.Internal.LazyInternalContext.InitializeDatabase()

       at System.Data.Entity.Internal.InternalContext.ForceOSpaceLoadingForKnownEntityTypes()

       at System.Data.Entity.DbContext.System.Data.Entity.Infrastructure.IObjectContextAdapter.get_ObjectContext()

       at Geophysical.Skimmer.Services.Scheduler.Repository.ModelContainer..ctor() in C:\Projects\GeophysicalInsights\src\Development\Geophysical.Skimmer\Geophysical.Skimmer.Services\Scheduler\Repository\Model.Context.cs:line 28

       --- End of inner exception stack trace ---

    I have spent almost 2 days trying every permutation and sequence I can think of, and still get this same exception. For example, I deleted the InitialCreate row from MigrationHistory and did my own "initial migration" (using -ignorechanges). Then added the Test property and ran add-migration.   Gets same exception. I then left the InitialCreate row in MigrationHistory, and ran my my own initial migration w/-ignorechanges, add Test property, the ran add-migration. Gets same exception. etc, etc, etc...

    Could this be related to a conflict with our DatabaseInitializer code? (notice the last entry in the stack trace).

    I'm stuck, and this needs to be ready for field deployment in a very few days...

    DadCat

    Configuration.cs:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Data.Entity;
    using System.Data.Entity.Migrations;

    namespace Services.Migrations
    {
        internal sealed class App : DbMigrationsConfiguration<Services.App.Repository.ModelContainer>
        {
            public App()
            {
                AutomaticMigrationsEnabled = false;
                MigrationsNamespace = "Services.App.Repository.Migrations";
            }

            protected override void Seed(Services.App.Repository.ModelContainer context)
            {
      
            }
        }

        internal sealed class Catalog : DbMigrationsConfiguration<Services.Catalog.Repository.ModelContainer>
        {
            public Catalog()
            {
                AutomaticMigrationsEnabled = false;
                MigrationsNamespace = "Services.Catalog.Repository.Migrations";
            }

            protected override void Seed(Services.Catalog.Repository.ModelContainer context)
            {
     
            }
        }

        internal sealed class Portfolio : DbMigrationsConfiguration<Services.PortfolioManagement.Repository.ModelContainer>
        {
            public Portfolio()
            {
                AutomaticMigrationsEnabled = false;
                MigrationsNamespace = "Services.PortfolioManagement.Repository.Migrations";
            }

            protected override void Seed(Services.PortfolioManagement.Repository.ModelContainer context)
            {
     
            }
        }

        internal sealed class Scheduler : DbMigrationsConfiguration<Services.Scheduler.Repository.ModelContainer>
        {
            public Scheduler()
            {
                AutomaticMigrationsEnabled = false;
                MigrationsNamespace = "Services.Scheduler.Repository.Migrations";
            }

            protected override void Seed(Services.Scheduler.Repository.ModelContainer context)
            {
     
            }
        }
    }

    Thursday, July 05, 2012 1:50 PM
  • Based on what I saw in the exception, I commented out the bold line below:

    namespace Services.Scheduler.Repository
    {
        using System;
        using System.Data.Entity;
        using System.Data.Entity.Infrastructure;
     
        public partial class ModelContainer : DbContext
        {
         static ModelContainer()
            {
           //     Database.SetInitializer(new DatabaseInitalizer());
            }

    ... and I can then run add-migration (and update-database) without errors.

    So, how do we keep the ability to initialize the database if it doesn't exist, and also work with Migrations?

    DadCat

    Thursday, July 05, 2012 2:40 PM
  • I was able to prevent the exception in add-migration command by changing my code to only invoke Database.SetInitializer when ModelContainer was being used by the application (or unit tests), and not invoke it when invoked by add-migration

    But it's not clear that I should continue to use DeleteDatabaseIfNotExists strategy when Migrations.  Should I use MigrateDatabaseToLatestVersion instead?

    But does that strategy work for explicity migrations?  Some of the docs seem to imply it's for automatic migrations.

    DadCat

    • Marked as answer by DadCat Friday, July 13, 2012 3:02 PM
    Thursday, July 05, 2012 10:10 PM
  • Hi DadCat,

    If you are using MigrsateDatabaseToLatestVersion, the database will be updated to the latest version when execute 'update-database' command. So I still suggest you to set it as false, it is more flexible.

    Best Regards


    Allen Li [MSFT]
    MSDN Community Support | Feedback to us

    Monday, July 09, 2012 8:47 AM