Home > other >  How does Entity Framework 6 order migrations
How does Entity Framework 6 order migrations

Time:11-20

What's the order of the migrations that get run when the db context is configured with MigrateDatabaseToLatestVersion? The autogenerated migration classes don't seem to contain any ordering. The only place that seems to have a clue about the order is the migration filename / the timestamp - but that doesn't seem likely or available at runtime... right?

CodePudding user response:

The initial migration name is actually what is used. This is also the same as the initial file name but you can obviously change that.

In EntityFramework, when you generate a migration, you may be familiar with editing the file to customize the migration.

    public partial class InitialCreate : DbMigration
    {
        public override void Up()
        {
            CreateTable(
                "dbo.Blogs",
                c => new
                    {
                        BlogId = c.Int(nullable: false, identity: true),
                        Name = c.String(),
                    })
                .PrimaryKey(t => t.BlogId);
            
        }
        
        public override void Down()
        {
            DropTable("dbo.Blogs");
        }
    }

But a designer file is also generated and it has a few properties that you shouldn't edit:

[GeneratedCode("EntityFramework.Migrations", "6.4.4")]
public sealed partial class InitialCreate : IMigrationMetadata
{
    private readonly ResourceManager Resources = new ResourceManager(typeof(InitialCreate));
        
    string IMigrationMetadata.Id
    {
        get { return "202111200213248_InitialCreate"; }
    }
        
    string IMigrationMetadata.Source
    {
        get { return null; }
    }
        
    string IMigrationMetadata.Target
    {
        get { return Resources.GetString("Target"); }
    }
}

In the source code of EF6, you can see the migrations are reflected from your migration assembly:
Every class that inherits from DbMigration is used and then ordered by the Id property.

_migrations
    = (from t in migrationsAssembly.GetAccessibleTypes()
        where t.IsSubclassOf(typeof(DbMigration))
                && typeof(IMigrationMetadata).IsAssignableFrom(t)
                && t.GetPublicConstructor() != null
                && !t.IsAbstract()
                && !t.IsGenericType()
                && t.Namespace == migrationsNamespace
        select (IMigrationMetadata)Activator.CreateInstance(t))
        .Where(mm => !string.IsNullOrWhiteSpace(mm.Id) && mm.Id.IsValidMigrationId())
        .OrderBy(mm => mm.Id)
        .ToList();

Even if you rename the files, the Id will still have its initial value when you created the migration keeping the migrations in lexical and chronological order as EF6 sees it.

It's pretty much the same for EFCore except that it has moved from a property to an attribute on the designer file:

    [DbContext(typeof(MyContext))]
    [Migration("20211118001328_InititialCreate")]
    partial class Init {}

And EFCore looks for that attribute on classes that inherit from Migration.

var items
    = from t in Assembly.GetConstructibleTypes()
        where t.IsSubclassOf(typeof(Migration))
            && t.GetCustomAttribute<DbContextAttribute>()?.ContextType == _contextType
        let id = t.GetCustomAttribute<MigrationAttribute>()?.Id
        orderby id
        select (id, t);
  • Related