Discussion Entity Framework 4.3 - DbMigrations add identity column "bug"

  • Wednesday, April 11, 2012 10:01 PM
     
      Has Code
    Hi all! There are some wrong thing with Migration Commands generations.
    First I have some POCO entity called Developer. It's look like this:

    public class Developer : INotifyPropertyChanged
        {
            private int _developerId;
    
            public int DeveloperId
            {
                get
                {
                    return _developerId;
                }
                set
                {
                    _developerId = value;
                    NotifyPropertyChanged("DeveloperId");
                }
            }
          
    For test purpose I wrote generic repository and need to apply IKeyItem<int> to Developer class:

    public class Developer : INotifyPropertyChanged, IKeyItem<int>
        {
            private int _developerId;
    		
            public int ID
            {
                get
                {
                    return _developerId;
                }
                set
                {
                    _developerId = value;
                    NotifyPropertyChanged("DeveloperId");
                }
            }
          
    There are IKeyItem<TKey> definition:

     public interface IKeyItem<TKey>
            where TKey : struct
        {
            TKey ID { get; set; }
        }


        
    After this I done steps as all time before - Add-Migration, Update-Database and always it ended success. But not this time:

    PM> Add-Migration GenericKeyAdded
    Scaffolding migration 'GenericKeyAdded'.
    The Designer Code for this migration file includes a snapshot of your current Code First model. This snapshot is used to calculate the changes to your model when you scaffold the next migration. If you make additional changes to your model that you want to include in this migration, then you can re-scaffold it by running 'Add-Migration 201204112133264_GenericKeyAdded' again.
    PM> Update-Database
    Specify the '-Verbose' flag to view the SQL statements being applied to the target database.
    Applying explicit migrations: [201204112133264_GenericKeyAdded].
    Applying explicit migration: 201204112133264_GenericKeyAdded.
    System.Data.SqlClient.SqlException (0x80131904): Multiple identity columns specified for table 'Developers'. Only one identity column per table is allowed.
       at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection)
       at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection)
       at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning()
       at System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj)
       at System.Data.SqlClient.SqlCommand.RunExecuteNonQueryTds(String methodName, Boolean async)
       at System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(DbAsyncResult result, String methodName, Boolean sendToPipe)
       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.ExecuteStatements(IEnumerable`1 migrationStatements)
       at System.Data.Entity.Migrations.Infrastructure.MigratorBase.ExecuteStatements(IEnumerable`1 migrationStatements)
       at System.Data.Entity.Migrations.DbMigrator.ExecuteOperations(String migrationId, XDocument targetModel, IEnumerable`1 operations, Boolean downgrading)
       at System.Data.Entity.Migrations.DbMigrator.ApplyMigration(DbMigration migration, DbMigration lastMigration)
       at System.Data.Entity.Migrations.Infrastructure.MigratorLoggingDecorator.ApplyMigration(DbMigration migration, DbMigration lastMigration)
       at System.Data.Entity.Migrations.DbMigrator.Upgrade(IEnumerable`1 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.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()
    Multiple identity columns specified for table 'Developers'. Only one identity column per table is allowed.

    After this I check GenericKeyAdded migration class code:

    public partial class GenericKeyAdded : DbMigration
        {
            public override void Up()
            {
                AddColumn("Developers", "ID", c => c.Int(nullable: false, identity: true));
                DropPrimaryKey("Developers", new[] { "DeveloperId" });
                AddPrimaryKey("Developers", "ID");
                DropColumn("Developers", "DeveloperId");
            }
    
            public override void Down()
            {
                AddColumn("Developers", "DeveloperId", c => c.Int(nullable: false, identity: true));
                DropPrimaryKey("Developers", new[] { "ID" });
                AddPrimaryKey("Developers", "DeveloperId");
                DropColumn("Developers", "ID");
            }
        }

        And as we see there are one problem - first call add new identity column in table with another identity existed.
        My solution is to change calls order in Up method:
        
        
    public override void Up()
            {
                DropPrimaryKey("Developers", new[] { "DeveloperId" });
                DropColumn("Developers", "DeveloperId");
                AddColumn("Developers", "ID", c => c.Int(nullable: false, identity: true));
                AddPrimaryKey("Developers", "ID");
            }
     After this all works excellent:
    PM> Update-Database
    Specify the '-Verbose' flag to view the SQL statements being applied to the target database.
    Applying explicit migrations: [201204112133264_GenericKeyAdded].
    Applying explicit migration: 201204112133264_GenericKeyAdded.    
       

All Replies

  • Sunday, April 15, 2012 5:15 AM
     
     
    I'll have a test!

    Fighting like Allen Iverson. Neve give up!

  • Monday, April 16, 2012 8:33 PM
    Moderator
     
     

    Hello,

    This is a pretty complex scenario and would be hard for Migrations to work out what code to generate. Our recommendation would be to do exactly what you did and edit the scaffolded code. Another alternative is to make the changes in two separate steps (i.e. drop the old column, Add-Migration, Update-Database... then add the new one).

    ~Rowan


    The *Pre-Release* Entity Framework Forum will be closing soon. We are seeing a lot of great Entity Framework questions (and answers) from the community on Stack Overflow. As a result, our team is going to spend more time reading and answering questions posted on Stack Overflow. We would encourage you to post questions on Stack Overflow using the entity-framework tag. We will also continue to monitor the Entity Framework forum.

  • Sunday, April 22, 2012 7:00 PM
     
     
    Because ID is Primary Key I think that two steps scenario can be wrong, or not?