0

I created a database schema using code-first. I created a base class for my models.

public abstract BaseObject {
    public long Id {get;set;}
}

and a Country class extending my BaseObject.

public Country : BaseObject {
    public string Name {get;set;}
}

I created a Seed method in the IEntityTypeConfiguration<Country> class for Country

public class CountryConfiguration : IEntityTypeConfiguration<Country>
{
    public void Configure(EntityTypeBuilder<Country> builder)
    {
        builder.HasData(new Country[] {new Country {Id = 1, Name = "Canada"}, 
            new Country{Id = 2, Name = "United-States"}
        });
    }
}

Later on I added IsActive in BaseObject and therefore added IsActive in my seed. I know that I could have set the default value for IsActive. But the problem is that not every object is active upon creation (Business rule mandates).

public class CountryConfiguration : IEntityTypeConfiguration<Country>
{
    public void Configure(EntityTypeBuilder<Country> builder)
    {
        builder.HasData(new Country[] {
            new Country{Id = 1, Name = "Canada", IsActive = true}, 
            new Country{Id = 2, Name = "United-States", IsActive = true}
        });
    }
}

The problem is that when I run Add-Migration the Seed for Country is not regenerated therefore when I run Update-Database the IsActive column is set to false automatically.

Is there any way to for EFCore to regenerate the Seed data?

EDIT: The migration containing the original Seed is one the first migration. We have currently 15 or so.

I want to know how to force a seed regeneration without having to redo any migrations.

Chax
  • 1,041
  • 2
  • 14
  • 36

1 Answers1

1

You can either remove the last migration using Remove-Migration and recrete or add a migration with a different name, like Add-Migration SeedDataUpdated (If this migration is not the last migration. check these answers on how to roll back), otherwise there is no command for regenerating/updating migrations.

If you removed last migration and created the migration again, it should look like this. (Remove-Migration -> Add-Migration SeedData)

protected override void Up(MigrationBuilder migrationBuilder)
{
    migrationBuilder.AddColumn<bool>(
        name: "IsActive",
        table: "Users",
        type: "bit",
        nullable: false,
        defaultValue: false);

    migrationBuilder.InsertData(
        table: "Users",
        columns: new[] { "Id", "Name", "IsActive" },
        values: new object[] { 1, "Canada", true });

    migrationBuilder.InsertData(
        table: "Users",
        columns: new[] { "Id", "Name", "IsActive" },
        values: new object[] { 2, "United-States", true });
}

If you created a new migration (Add-Migration SeedDataUpdated), it should look like this.

protected override void Up(MigrationBuilder migrationBuilder)
{
    migrationBuilder.AddColumn<bool>(
        name: "IsActive",
        table: "Countries",
        type: "bit",
        nullable: false,
        defaultValue: false);

    migrationBuilder.UpdateData(
        table: "Countries",
        keyColumn: "Id",
        keyValue: 1,
        column: "IsActive",
        value: true);

    migrationBuilder.UpdateData(
        table: "Countries",
        keyColumn: "Id",
        keyValue: 2,
        column: "IsActive",
        value: true);
}
Nishan
  • 3,644
  • 1
  • 32
  • 41
  • We ended up removing all of the migrations just to regenerate the Seed data. The migration containing the original Seed was the third migration out of 15. We are lucky that the project is still in an early phase. Good to know that there is no out-of-the-box method for regenerating Seeds – Chax Jul 24 '21 at 22:34
  • If creating a new seed migration with new data is not what you want, then that is the only way, but later your application requirements can change again and you might want to change the seed again, then the only option is to create a new migration with new data, that is infact is why we need migrations in the first place. **Removing everything defeats the purpose of having migrations!** – Nishan Jul 25 '21 at 14:40
  • That is exactly my points. Adding a new migration with the updated data did not solved the problem. The original migration took precedence and therefore the data is not updated. I'm looking for a way to use Seeding with EFCore, but if I cannot update my seed data with new migrations, I will have to resort to another option. You answer is still helpful. The problem is that EFCore does not generate the `UpdateData` like you show in your example. Do you have any idea what could be causing that? – Chax Jul 25 '21 at 15:41
  • 1
    Can't say what's causing this without some more investigations, It could be because you're using Entity Type Configurations, not sure, may be create an empty migration and add `UpdateData` manually as a workaround? or use Sql() method to run sql update query in a migration. See https://learn.microsoft.com/en-us/ef/core/managing-schemas/migrations/operations#using-migrationbuildersql and https://dotnetthoughts.net/creating-stored-procs-in-efcore-migrations/ for how to use Sql() method. – Nishan Jul 25 '21 at 19:08