5

I use EF Core and want to add predefined data. It can be done by the following code:

            modelBuilder.Entity<UserPage>().HasData(new UserPage()
            {
                Name = "Homepage",
                Editable = true,
                Path = "path"
            });

this part of code validates whether UserPage object with exactly data exists and if not, creates it But I want to add new record only when record with Name = "Homepage" does not exist, otherwise no. Code above will add new record even if record with name "Homepage" already exists, but Editable = false for example. I want to validate it, I try:

        if (UserPages.Where(p => p.Name.Equals("Homepage", StringComparison.InvariantCultureIgnoreCase)).FirstOrDefault() == null)
        {
            modelBuilder.Entity<UserPage>().HasData(new UserPage()
            {
                Name = "Homepage",
                Editable = true,
                Path = "path"
            });
        }

but I get an error:

An attempt was made to use the model while it was being created. A DbContext instance cannot be used inside OnModelCreating in any way that makes use of the model that is being created.

Oleg Sh
  • 8,496
  • 17
  • 89
  • 159

1 Answers1

7

That is outside the context of "database seeding". Seeding "makes sure" data exists as you specify it when the database is being created/updated and it's to be done at "migration time", when you may not have a database configured at all (at the point that code is executing, you are defining the model to EF: you may not even have a ready real database to query data from: that's the error you are seeing).

If what you are after is handling some logic on the database itself, and not at "database design time", then don't do it on the model creation, and run that logic when your app starts (or at any other point in time), after the database is created and seeded .

Jcl
  • 27,696
  • 5
  • 61
  • 92
  • But HasData, if the row has been changed subsequently, overwrites the row with the old seed data. It doesn't just seed, it overwrites the changed row with old data, when a new migration is applied. How do you get around this? I know we can create an sql script or a separate app to seed data, but that is not an option. – GoWiser Jul 26 '22 at 09:56
  • 1
    @GoWiser as specified in the answer... if you want to have logic on the data, I'd say that's outside "seeding", which is meant to have an specific state when applying a migration. If you want something like "have this data unless it was already there", then I'd say that's part of the runtime logic, and not of the migration/seeding – Jcl Jul 26 '22 at 10:58
  • I am not talking about logic in the data. The initial data should NOT be re-seeded, when we make database design changes. We don't want the database polluted with a migration history, while developing a prototype. And we don't want multiple EF apps. And it's NOT a runtime issue, the seed data should be specified in the (single) EF Core app, before we run anything, and before we run 'dotnet ef migrations add InitialCreate'. I don't see how this is possible in the current EF Core. – GoWiser Aug 04 '22 at 10:24
  • Sorry for caps, included them for readability. Ie. data seeding for when the database is created, not updated. I don't see this as logic in the seed data, I see it as a flaw in the EF framework. – GoWiser Aug 04 '22 at 10:31