Craig W.
Craig W.

Reputation: 18155

Seeding variable data using EF Core 2.2

In all the examples and articles I've seen about seeding data using EF Core all of the data is hard-coded. I have a need to seed some data where part of it is variable. My model is:

public class Customer
{
    [Key]
    public Guid Id { get; set; }

    public string ApiKey { get; set; }
}

Specifically, I want the ApiKey to contain a different value each time the seed operation runs. That way I get a different value for each environment (development, QA, production).

I created a method to generate a unique value and added the following to my OnModelCreating method.

modelBuilder.Entity<Customer>().HasData(new Customer
{
    Id = Guid.NewGuid(),
    ApiKey = GenerateApiKey()
});

The problem, as you have probably guessed, is that the call to GenerateApiKey happens when the migration is created so the value generated by GenerateApiKey is effectively hard-coded into the InsertData call.

migrationBuilder.InsertData(
    table: "Customers",
    columns: new[] { "Id", "ApiKey" },
    values: new object[] 
    { 
        new Guid("bcde0c82-ad26-47fb-bd5f-1ad552d2b8f0"),
        "56+hhUTjPwz0FM9uwYg19M5rfq6aUgmNde15Frn6TFY=" 
    });

In EF 6.x I accomplished this using the Seed method of my DbMigrationsConfiguration subclass.

I realize I could modify the migration, but we're at a stage of development where we are dropping and recreating the database during changes and that would require every developer remember to do that when they regenerate the initial migration. I'd rather make it a little more foolproof than that.

Upvotes: 2

Views: 352

Answers (1)

PmanAce
PmanAce

Reputation: 4323

You could always run a seed method once your host is ready like so (this is how I do it in 2.1):

public static void Main(string[] args)
{
    CreateWebHostBuilder(args).Build().Seed().Run();
}

...

public static class WebHostExtensions
{
    public static IWebHost Seed(this IWebHost host)
    {
        using (var scope = host.Services.CreateScope())
        {
            var services = scope.ServiceProvider;
            var loggerFactory = services.GetRequiredService<ILoggerFactory>();
            var context = services.GetRequiredService<MsbContext>();

            // do whatever you need here with your data before migrations
            ...
            context.Database.Migrate();

            // do whatever you need here with your data after migrations
            ...
        }
    }
}

Upvotes: 1

Related Questions