2

Closed

Code First :: When having model with 2 discriminator columns, running it the first time works, second time (same model) throws 'Model has Changed' exception, also breaks Migrations

description

When running the following repro TWICE:

namespace Repro
{
using System.Data.Entity;
using System.Linq;

public class MyContext : DbContext
{
    public DbSet<Parent> Entities { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Child1>().Map(m =>
        {
            m.Requires("Disc1").HasValue(true);
            m.Requires("Disc2").HasValue(false);
        });

        modelBuilder.Entity<Child2>().Map(m =>
        {
            m.Requires("Disc2").HasValue(true);
            m.Requires("Disc1").HasValue(false);
        });
    }
}

public abstract class Parent
{
    public int Id { get; set; }
}

public class Child1 : Parent
{
}

public class Child2 : Parent
{
}

class Program
{
    static void Main(string[] args)
    {
        using (var context = new MyContext())
        {
            context.Entities.ToList();
        }
    }
}
}


First time everything is fine, but second time it throws the following exception (which shouldn't happen, as model did not change):

System.InvalidOperationException: The model backing the 'My Context' 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.CreateDatabaseIfNotExists1.InitializeDatabase(TContext context)
at System.Data.Entity.Internal.InternalContext.<>c__DisplayClassc
1.<CreateInitializationAction>b__b()
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.RetryAction1.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.GetEntitySetAndBaseTypeForType(Type entityType)
at System.Data.Entity.Internal.Linq.InternalSet1.Initialize()
at System.Data.Entity.Internal.Linq.InternalSet
1.GetEnumerator()

file attachments

Closed May 24, 2013 at 7:01 PM by lajones
Fixed.

comments

maumar wrote Mar 14, 2013 at 1:31 AM

Additional investigation notes:

When doing:
var sb = new StringBuilder();
EdmxWriter.WriteEdmx(context, XmlWriter.Create(sb));

I get same results both times.



Exception gets thrown when comparing 2 attached models (using ModelDiffer)

maumar wrote Mar 14, 2013 at 1:33 AM

differences are:

Renamed Columns:
Disc1 -> Disc2
Disc2 -> Disc1

Removed Tables:
__MigrationHistory

maumar wrote Mar 14, 2013 at 1:41 AM

This may lead to silent data loss, if using DropCreateDatababaseIfModelChanges. Eg the following code run twice:
        Database.SetInitializer(new DropCreateDatabaseIfModelChanges<MyContext>());
        using (var context = new MyContext())
        {
            Console.WriteLine("Before: " + context.Entities.Count());
            context.Entities.Add(new Child1());
            context.Entities.Add(new Child2());
            context.Entities.Add(new Child1());
            context.Entities.Add(new Child2());
            context.Entities.Add(new Child1());
            context.SaveChanges();
            Console.WriteLine("After: " + context.Entities.Count());
        }

Produces the same result every time (added entires being lost):

Before: 0
After: 5
Press any key to continue . . .

maumar wrote Mar 14, 2013 at 1:43 AM

Also, if using Migrations, and setting initializer to the migrations initializer I get the following exception:

System.Data.SqlClient.SqlException (0x80131904): Error: The new name 'Disc2' is already in use as a COLUMN name and would cause a duplicate that is not permitted.
at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action1 wrapCloseInAction)
at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action
1 wrapCloseInAction)
at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)
at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady)
at System.Data.SqlClient.SqlCommand.RunExecuteNonQueryTds(String methodName, Boolean async, Int32 timeout)
at System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(TaskCompletionSource1 completion, String methodName, Boolean sendToPipe, Int32 timeout, Boolean asyncWrite)
at System.Data.SqlClient.SqlCommand.ExecuteNonQuery()
at System.Data.Entity.Migrations.DbMigrator.ExecuteSql(DbTransaction transaction, MigrationStatement migrationStatement)
at System.Data.Entity.Migrations.Infrastructure.MigratorLoggingDecorator.ExecuteSql(DbTransaction transaction, MigrationStatement migrationStatement)
at System.Data.Entity.Migrations.DbMigrator.ExecuteStatementsInternal(IEnumerable
1 migrationStatements, DbConnection connection)
at System.Data.Entity.Migrations.DbMigrator.<>c__DisplayClass4c.<ExecuteStatements>b__48()
at System.Data.Entity.SqlServer.DefaultSqlExecutionStrategy.<>c__DisplayClass1.<Execute>b__0()
at System.Data.Entity.SqlServer.DefaultSqlExecutionStrategy.Execute[TResult](Func1 func)
at System.Data.Entity.SqlServer.DefaultSqlExecutionStrategy.Execute(Action action)
at System.Data.Entity.Migrations.DbMigrator.ExecuteStatements(IEnumerable
1 migrationStatements)
at System.Data.Entity.Migrations.Infrastructure.MigratorBase.ExecuteStatements(IEnumerable1 migrationStatements)
at System.Data.Entity.Migrations.DbMigrator.ExecuteOperations(String migrationId, XDocument targetModel, IEnumerable
1 operations, Boolean downgrading, Boolean auto)
at System.Data.Entity.Migrations.DbMigrator.AutoMigrate(String migrationId, XDocument sourceModel, XDocument targetModel, Boolean downgrading)
at System.Data.Entity.Migrations.Infrastructure.MigratorLoggingDecorator.AutoMigrate(String migrationId, XDocument sourceModel, XDocument targetModel, Boolean downgrading)
at System.Data.Entity.Migrations.DbMigrator.Upgrade(IEnumerable1 pendingMigrations, String targetMigrationId, String lastMigrationId)
at System.Data.Entity.Migrations.Infrastructure.MigratorLoggingDecorator.Upgrade(IEnumerable
1 pendingMigrations, String targetMigrationId, String lastMigrationId)
at System.Data.Entity.Migrations.DbMigrator.UpdateInternal(String targetMigration)
at System.Data.Entity.Migrations.DbMigrator.<>c__DisplayClass19.<Update>b__18()
at System.Data.Entity.Migrations.DbMigrator.EnsureDatabaseExists(Action mustSucceedToKeepDatabase)
at System.Data.Entity.Migrations.Infrastructure.MigratorBase.EnsureDatabaseExists(Action mustSucceedToKeepDatabase)
at System.Data.Entity.Migrations.DbMigrator.Update(String targetMigration)
at System.Data.Entity.Migrations.Infrastructure.MigratorBase.Update(String targetMigration)
at System.Data.Entity.Migrations.Design.ToolingFacade.UpdateRunner.RunCore()
at System.Data.Entity.Migrations.Design.ToolingFacade.BaseRunner.Run()

maumar wrote May 22, 2013 at 9:06 PM

Fixed in 433ceb8555087102aeec8564d9c905e839bef891

lajones wrote May 24, 2013 at 7:01 PM

Verified on VS2012 and VS vNext.