Data seeding database
So currently in my
program.cs
I have the following code:
Now, seeding only makes sense in a development environment and only has to be executed once. So would this be a proper way to go about it? My DataSeeder class basically creates objects of all my models, gives them mock values, and that I save to the database.40 Replies
To my understanding, once I call
SaveChanges()
on my DataContext
object, that's when they will staged for the next migration, please correct me if im wrong.
For instance in my
The moment I do _context.SaveChanges();
, all the changes I pushed to the context with: _context.TableName.AddRange( /* data here */ )
gets staged for the next migrations.Hello @joren,
you can check your enviorenment in program.cs using
app.Environment.IsDevelopment()
if this returns true you are in development, if the case is only debuggin
#if DEBUG
#end if
you can use this.
So when you release the application your enviorenment is going to be production(or the setting you set before) and the db is not going to be seed anymore
Savechanges method just redirect your query to the db, it's not related with migration at all
Migrations are strictly about model changes and its relations
and nothing to do with the values inside those tables then I assume
would make sense actually, as seeding wouldnt be migrating anything
what dictates the value it returns, the profile we use to run it ?
so this one, in release it would be
False
then I assumeEh, I guess its the
launchSettings.json
that dictates it
Yes, there is a environment variables you need to use
"ASPNETCORE_ENVIRONMENT": "Development"
Makes sense, so lets say its on development as it is now, would it try to seed it every time I run it ?
I assume so, which would make the startup time pretty inefficient
I might just add some compile time constant, that I can flip from True
to False
to disable seeding after the initial seeding locally...if that variable is set to development yes, If you don't want ta seed again and again, you could check the data with "any" method.
If you try to execute your program in release mode it should be changed I guess, let me check it
Any()
would be on a table, what if seeding was done manually and therefore is not 100% complete, then doing it on just one table would be wrong
you'd have to do a .Any()
check on each table, to see if it contains any data, if one of them does not, just seed it, else skip it
Would be cool if I could somehow iterate over the types in the Models
folder, call .Any()
on each, not sure if thats achievable in C#.
It has reflection, so it is doable I just checkedare you even trying to execute the db commands parallel? Any() just returns, if there is any data in the table. IF you added it it will true, thus you dont need to add any data to seed and you will return/continue
I mean prior to seeding, when the program starts, lets assume the db is seeded already
Even if you add your data manually when thread comes to Any() method it's going to return true or false according to it
I want to check if it's seeding
yes, but that'd mean I'd have to call
.Any
on each table individually
imagine you have 100 tables, no one will call .Any
on each table to check if it has data.
prior to seeding I could I guess, but then it always goes into the proces of seeding. Then I assume it should be seeded, and actually seed the table if its not populatedYes unfortunetly. Well in that case If you are adding any data to the 100 tables manually you already have long code, an any method wouldn't hurt ya?
you can register your code to the applicationstart event, thus it's absolutely going to work once. it'd be useless if you define a variable to the program cs because it only works once already
yeah true, one more thing thats bugging me:
got these models right, pretty standard stuff
my current seeder looks like this:
As you can see, im only really creating objects of
PokemonOwner
, which contains basically all the other models.
And somehow, for some reason, I suppose based on my relations with this model, it generates the other dummy data automatically for me
like, the Country
tables, Reviewer
table, etc. Seems to me like EF Core is doing some magic. It makes sense, as PokemonOwner
has an Owner
, a Country
, etc. So it not seeding the tables referenced wouldnt make much sense, though it looks a bit tricky and wonky.right, EF is an ORM which means it tries to sync your objects up with the database
It needs to create, ef core acts right, otherwise ef core couldn't create the entity.
if your object graph spans multiple entity types, they will all be tracked and updated
And assuming what I said is the case, a
.Any
call on PokemonOwner
only would be sufficient then no?
as PokemonOwner
in my case, requires all those other tables, therefore its granted they are seeded?if data existing in that table is enough of an indicator for you that it's seeded, yes
yes it' seems enough in this case
I mean, lets say the database is seeded except
Owner
, then PokemonOwner
's table wouldnt be able to be filled properly
it would have NULL I suppose, its possible in the database, would .Any()
give True
?why would it be seeded except for that table if your seeding code is guaranteed to add data to it?
well, lets assume they do not use my seeder, manually seed it locally, wouldnt know why but lets assume they did
given this is the PokemonOwner table, would
.Any()
return true?Any tells you if any rows exist, so yes
ah I see, so to be waterproof some reflective way to iterate over the models, and to call .Any on each model
would be better, in theory
yes, if you want to avoid seeding if there is anything in the DB at all you'll have to check each set
any libs that implemented this that you know of
it's basically just a loop
iterate over the
Models
folder, take the class type, call a method on ityou can create an empty migration and can do whatever in there you want, there is no need to use library for only checking .Any()
you'd be better off using the model built by the dbcontext
than doing reflection
you mean in the OnModelCreation and the
HasData()
?i mean a dbcontext has a
.Model
property that gives you access to your db model
where you can get the entity types and do something with them, etcoh really
that'd make it easy af
lol
let me check this one second
the only problem is no non-generic way to get a dbset
wait, moment I think I messed it up
Well I got it to work, here is the code that works. It correctly checks if any table is seeded, if not it re-seeds it fully according to my seeding input.
that is if anyone is interested in this, or would like to use it.