2

Right now I am in development and use the code below to seed the lookup tables. But once it is in production and I want to add additional data how do I do that ? Do I use some sort of AddOrUpdate (not in core) in the seeding method ? Write a SQL script ?

 private static async Task SeedRfReportStateTypesAsync(PwdrsContext pwdrsContext)
    {
        if (pwdrsContext.RfReportStateTypes.Any())
        {
            return;
        }

        List<RfReportStateType> rfReportStateTypes = new List<RfReportStateType>()
        {
            new RfReportStateType() { Name = "Draft", UpdatedBy = "SYSTEM", UpdatedOn = DateTime.Now}, //4
            new RfReportStateType() { Name = "Review", UpdatedBy = "SYSTEM", UpdatedOn = DateTime.Now}, //3
            new RfReportStateType() { Name = "Stage", UpdatedBy = "SYSTEM", UpdatedOn = DateTime.Now}, //2
            new RfReportStateType() { Name = "Prod", UpdatedBy = "SYSTEM", UpdatedOn = DateTime.Now} //1
        };

        pwdrsContext.RfReportStateTypes.AddRange(rfReportStateTypes);
        await pwdrsContext.SaveChangesAsync();
    }
punkouter
  • 5,170
  • 15
  • 71
  • 116

2 Answers2

5

The way you're seeding currently is deprecated. If you handle the seeding as you're supposed to, then inserts, updates, etc. of the seed data are handled automatically by EF Core. It is now done via fluent config in OnModelCreating in your context:

modelBuilder.Entity<RfReportStateType>().HasData(
    new RfReportStateType { Id = 4, Name = "Draft" },
    new RfReportStateType { Id = 3, Name = "Review" },
    new RfReportStateType { Id = 2, Name = "Stage" },
    new RfReportStateType { Id = 1, Name = "Prod" }
);

A few notes. First, you must include the id. This is so EF Core knows what items to insert, update, or delete. New ids will be inserted, removed ids will be deleted, and anything existing will be updated. It also makes it possible to create relationships and such since the ids are known. Second, things like UpdatedOn should be handled via an auto-generated value, rather than specified in the seed data, as otherwise it will trigger an update on every run, since DateTime.Now will always be different, one run to the next. That way, you can also specify if it should be generated only on add or update, making it perfect for things like created/updated dates. In general, your seed data should only contain static values, so that updates are triggered only when you specifically change one of those values. Third, you could include UpdatedBy, if you like, but that would likely be better handled by a default value on the column, i.e. it's SYSTEM unless something more specific is passed.

Chris Pratt
  • 232,153
  • 36
  • 385
  • 444
  • could I do the deprecated way for v1 ? And they any updates after that I could use the ModelBuilder way ? Since once it is in production my deprecated way would never run – punkouter Jan 13 '20 at 18:40
  • Perhaps, but why? The ModelBuilder way works in either scenario. Do it once for all, and call it day. – Chris Pratt Jan 13 '20 at 18:42
0

Implement FluentMigration

This will allow you to Seed data on every Migration you apply.

You could also make a migration just to insert/update data this will run on every instance (dev/qa/stagging/production).

See this post: https://stackoverflow.com/a/30583692/12649354

ljcordero
  • 185
  • 6
  • You mean OnModelCreating I would create the entites there which would then create the migration files that would add the entities when run correct? How does this compare to just manually putting them in the Migration class? It seems I can do it both ways. Looking at this article: 1a vs 1b https://www.thereformedprogrammer.net/handling-entity-framework-core-database-migrations-in-production-part-1/ – punkouter Jan 13 '20 at 18:32
  • @punkouter the best way is to put the seed on Migration classes. If you do on OnModelCreating you will have to check if those seeds were applied with custom code, but this way on every migration you can seed data and EF will take care if they were applied. – ljcordero Jan 14 '20 at 13:23