1

I´ve got a little program, which uses EFCore 5.0.12 also I have added a Company and Person model to the program which are my DB-Models. Then I´ve added a migration to initial create the tables.

Then I´ve added an Address model for the Person model, which should also be a DB-Model. The did a second migration, which you can see below. But if I run my code again it seems like it want to migrate both Migrations.

How can I migrate a Database from specific migration.

Here my code:

This is my TestDbContext which should do all the Db-work.

public class TestDbContext : DbContext
{
    public DbSet<Company> Companies { get; set; }

    private string _dbPath = Path.Combine(".", "TestDb.sqlite");

    public TestDbContext() 
    {
        if (File.Exists(_dbPath))
            Database.Migrate();
        else Database.EnsureCreated();
    }

    protected override void OnConfiguring(Microsoft.EntityFrameworkCore.DbContextOptionsBuilder optionsBuilder)
    {
        if (!Directory.Exists(Path.GetDirectoryName(_dbPath)))
            Directory.CreateDirectory(Path.GetDirectoryName(_dbPath));

        try
        {
            optionsBuilder.UseSqlite($"Data Source={Path.GetFullPath(_dbPath)}");
        }
        catch (Exception ex)
        {
            //Log.Error("Could not create DB");
            //Log.Error(ex);

            return;
        }
    }

Also I´ve got this Company-Model which inherits from BaseEntry which holds an ID field as

public class Company : BaseEntry
{
    public List<Person> Employees { get; set; } = new List<Person>();
}

The Person-Model also inherits from BaseEntry to get a PrimaryKey also.

public class Person : BaseEntry
{
    public string Name { get; set; }
    public string Firstname { get; set; }
    public Address Address { get; set; }
}

Address which should be added while migration.

public class Address : BaseEntry
{
    public string Street { get; set; }
    public uint Number { get; set; }
    public string City { get; set; }
}

And the BaseEntry which holds the ID field.

public abstract class BaseEntry
{
    [Key]
    public ulong Id { get; set; }
}

Here comes the first migration which ensures the tables content

    protected override void Up(MigrationBuilder migrationBuilder)
    {
        migrationBuilder.CreateTable(
            name: "Companies",
            columns: table => new
            {
                Id = table.Column<ulong>(type: "INTEGER", nullable: false)
                    .Annotation("Sqlite:Autoincrement", true)
            },
            constraints: table =>
            {
                table.PrimaryKey("PK_Companies", x => x.Id);
            });

        migrationBuilder.CreateTable(
            name: "Person",
            columns: table => new
            {
                Id = table.Column<ulong>(type: "INTEGER", nullable: false)
                    .Annotation("Sqlite:Autoincrement", true),
                Name = table.Column<string>(type: "TEXT", nullable: true),
                Firstname = table.Column<string>(type: "TEXT", nullable: true),
                CompanyId = table.Column<ulong>(type: "INTEGER", nullable: true)
            },
            constraints: table =>
            {
                table.PrimaryKey("PK_Person", x => x.Id);
                table.ForeignKey(
                    name: "FK_Person_Companies_CompanyId",
                    column: x => x.CompanyId,
                    principalTable: "Companies",
                    principalColumn: "Id",
                    onDelete: ReferentialAction.Restrict);
            });

        migrationBuilder.CreateIndex(
            name: "IX_Person_CompanyId",
            table: "Person",
            column: "CompanyId");
    }

    protected override void Down(MigrationBuilder migrationBuilder)
    {
        migrationBuilder.DropTable(
            name: "Person");

        migrationBuilder.DropTable(
            name: "Companies");
    }
}

Then here the second migration, which adds the Adress-Content to the DB:

    protected override void Up(MigrationBuilder migrationBuilder)
    {
        migrationBuilder.AddColumn<ulong>(
            name: "AddressId",
            table: "Person",
            type: "INTEGER",
            nullable: true);

        migrationBuilder.CreateTable(
            name: "Address",
            columns: table => new
            {
                Id = table.Column<ulong>(type: "INTEGER", nullable: false)
                    .Annotation("Sqlite:Autoincrement", true),
                Street = table.Column<string>(type: "TEXT", nullable: true),
                Number = table.Column<uint>(type: "INTEGER", nullable: false),
                City = table.Column<string>(type: "TEXT", nullable: true)
            },
            constraints: table =>
            {
                table.PrimaryKey("PK_Address", x => x.Id);
            });

        migrationBuilder.CreateIndex(
            name: "IX_Person_AddressId",
            table: "Person",
            column: "AddressId");

        migrationBuilder.AddForeignKey(
            name: "FK_Person_Address_AddressId",
            table: "Person",
            column: "AddressId",
            principalTable: "Address",
            principalColumn: "Id",
            onDelete: ReferentialAction.Restrict);
    }

    protected override void Down(MigrationBuilder migrationBuilder)
    {
        migrationBuilder.DropForeignKey(
            name: "FK_Person_Address_AddressId",
            table: "Person");

        migrationBuilder.DropTable(
            name: "Address");

        migrationBuilder.DropIndex(
            name: "IX_Person_AddressId",
            table: "Person");

        migrationBuilder.DropColumn(
            name: "AddressId",
            table: "Person");
    }
}

But this migration is never reached because the first migration fails because of Table already exists. My main question is, how to say EFCore that the DB is allready migrated to a specific point and it should only migrate from this point?

Felix Arnold
  • 839
  • 7
  • 35
  • Did you scaffold first? https://learn.microsoft.com/en-us/ef/core/managing-schemas/scaffolding?tabs=dotnet-core-cli – sommmen Dec 06 '21 at 08:27

1 Answers1

0

If you want to tell EF that your first migration already migrate. you can just manually add it to migration history table default table is __EFMigrationsHistory

MigrationId ProductVersion
2021061200000_initialize_blah_blah 5.0.1.2
your_migration_id version

and do migration again it will skip migration that already in the histories table

also if you just want to migrate specific migration you can tell it while you run migrate command

update-database -migration "your-migration"
Asakuraa Ranger
  • 577
  • 7
  • 18
  • Thank you @Asakuraa Ranger. How can I programmatly add this entries to this Table? – Felix Arnold Dec 06 '21 at 09:48
  • 1
    If your point is to migrate specific migration then you can do it from dbContext `yourDbContext.GetService().Migrate("your_migration");` – Asakuraa Ranger Dec 06 '21 at 20:22
  • If you want to add the record but you can't access database directly you can run raw Sql script from console command and also from code. this one : https://stackoverflow.com/questions/35184476/how-to-execute-raw-sql-query-using-entity-framework-without-having-to-use-a-mode and this one : https://stackoverflow.com/questions/14283082/how-do-i-force-entity-framework-to-mark-a-particular-migration-as-having-been-ap – Asakuraa Ranger Dec 06 '21 at 20:28