My seed data uses the HasData method for insert:
modelBuilder.Entity<SystemResource>().HasData(new[]
{
new SystemResource()
{
Id = 1,
Code = "roi-dev-003",
IsEnabled = true,
}
});
I would like to change the value of the Code property of generated seed data to a new value. Can it be done using seed data or is an sql update of DB needed?
The signature of the HasData method says it is used to generate data motion migration. How does a data motion migration work?
Update:
Changing the value of Code property and then running update-database has no effect:
PM> update-database
No migrations were applied. The database is already up to date.
Unfortunately, it doesn't appear that this functionality is supported in EFCore currently.
This article is a pretty in-depth overview of the HasData system. This line from it is relevant:
But HasData isn’t a silver bullet. Keep in mind that this feature is best for seed data that will remain static once it’s been inserted into the database.
I too have been looking for a good solution to this problem
Related
Inside of OnModelCreating, I want to be able to ignore a column if the database is on an older migration EF Core 5 throws an exception if I attempt to read from the database directly, or indirectly by querying the applied migrations. I'm not certian that it's even a good idea, since OnModelCreating is used during the migration 😩, but I'll burn that bridge when I cross it.
There are some examples on how one would do this with EF6, but they don't seem to apply anymore with EF Core.
While Ivan Stoev is right that --generally-- you should model the target database without outside input, the real world isn't always that clear-cut. In my particular case, there are multiple service instances (Azure Functions) that need to read and write to a single database. In order to maintain zero downtime, those Functions need to not read or write columns that don't yet exist.
I solved the problem the way Serge suggested. The database has a known version, populated with seed data that increments with every migration. On startup, the service reads that version with a regular old Microsoft.Data.Sql.SqlConnection. This version is then added to the IServiceCollection as a singleton to be used by the DbContext constructor.
When talking to an older database version, OnModelCreating does things like this:
builder.Entity<Widget>(w =>
{
// another option would be to use the migrations table instead of an integer
if (DatabaseVersion < ContextVersions.WidgetNewPropertyAddedVersion)
{
w.Ignore(w => w.NewProperty);
}
else
{
w.Property(w => w.NewProperty)
.HasDefaultValue(0);
}
});
The startup code also detects if it's been started by the Entity Framework tools and does not read the database version, instead assuming "latest". This way, we do not ignore new properties when building the migration.
Figuring out how to let the service instances know that the database has been upgraded and they should restart to get the new database model is an exercise left up to the reader. :)
I've created a new class, and EF will create a migration code when I'll do add-migration in Package Manager Console. Since this table is a classifier, I want to populate it with data and include this data in migration. I cannot use Seed method, since i'll be using my generated migration on production database later on.
Where should I hardcode the values for this table? I can edit the generated migration cs file, but this seems an inelegant solution. Could you recommend more proper place to define the data?
I think if you're goal is to populate your table for development/testing, there's no reason you shouldn't do you data seeding via the Seed method. You could always wrap the seed code for this table with an if block that checks your connection string values.
Edit:
If you plan to populate your table in your production database with the same data, it would certainly make sense to do so in the Up method of that specific migration that creates the table.
I'm using Entity Framework v4. I have followed the instructions in the Nerd Dinner tutorial. I'm currently in development mode (not released to any higher environments) and would like for tables to be recreated on each new deployment, since the models are still highly volatile and I don't care to retain data. However, this does not occur. Tables are not created/modified, or anything happening to the DB. If I move to a migrations model by using the Package Manager commands: enable-migrations, add-migration (initial), this works and uses my migrations. However, since I don't yet want to have granular migrations and only want my initial create script, I am forced to delete the migrations folder, redo the commands (enable-migrations, add-migration) and delete the database manually, every time I change anything.
How do I get the drop/create behavior of code first to occur?
Use DropCreateDatabaseAlways initializer for your database. It will always recreate database during first usage of context in app domain:
Database.SetInitializer(new DropCreateDatabaseAlways<YourContextName>());
Actually if you want to seed your database, then create your own initializer, which will be inherited from DropCreateDatabaseAlways:
public class MyInitializer : DropCreateDatabaseAlways<YourContextName>
{
protected override void Seed(MagnateContext context)
{
// seed database here
}
}
And set it before first usage of context
Database.SetInitializer(new MyInitializer());
If the database already exists and you want to make changes to your model, you use DropCreateDatabaseIfModelChanges<YourContextName>
I want to programmatically create the database create script for my EF 4.3 Code-First database. The database creates just fine using the standard DatabaseInitializer mechanisms, but the following code fails:
using(var dc = new MyContext())
{
var objContext = (IObjectContextAdapter)dc;
var script = objContext.ObjectContext.CreateDatabaseScript();
}
The exception I get is:
The store generated pattern 'Computed' is not supported for properties that are not of type 'timestamp' or 'rowversion'.
I do have a Computed column defined of type "string" but like i said, the database creates fine when created via the built-in DatabaseInitializer. Oddly enough, the resulting schema using this method doesn't actually create a computed column.
As to why I'm doing this, I have a script that runs post-create that drops this column and creates a bonafide computed column. Without specifying the column as computed in the EF mapping, it will attempt to assign that column a value upon inserts, which then fails.
Leaving database creation aside for a moment, setting “Computed” means that EF will not attempt to write the value of that column but will read the value that was (presumably) computer by the server each time the column is queried. From an EF perspective it is valid to have a computed column for any data type.
Now consider database creation from the EF model. EF doesn’t know what to do to create the computed column in the database, and indeed it may not even be possible to do it without triggers in certain databases depending on the type of the column. So in EF4 the decision was made to make CreateDatabaseScript throw in these situations.
However, EF 4.3 and later don’t use CreateDatabaseScript anymore when targeting SQL Server or SQL Server Compact. They instead use the Migrations pipeline. For the Migrations pipeline we decided to take a different approach because we felt that it was wrong for database creation to always throw for what could be a perfectly valid model. Especially considering you could have written your own SQL in the migration that added a trigger or some other mechanism to make the database create a valid computed column.
So this is why you see the database being created by EF 4.3 (but without doing anything to make the column computed) but then you see the same model throw when trying to use CreateDatabaseScript which uses the older, non-Migrations mechanisms.
The way to fix this is to have Migrations create the scripts instead of using CreateDatabaseScript.
I have been using Entity Framework 4.3 on an existing database and I have a couple of scenarios that I am trying to cater for.
Firstly, if I delete my database I would like to EF to recreate if from scratch - I have successfully used a CreateDatabaseIfNotExists database initialiser for this.
Secondly, if I update my model and the database already exists I would like the database to be updated automatically - I have successfully used Entity Framework 4.3 Migrations for this.
So here's my question. Say I add a new table to my model which requires some reference data, what it the best way to ensure that this data gets created both when the database intialiser runs and also when the migration runs. My desire is that the data gets created when I'm creating the db from scratch and also when the database gets updated as the result of a migration running.
In some EF migrations examples I have seen people use the SQL() function in the UP method of the migration to create seed data but if possible I would rather use the context to create the seed data (as you see in most database initialiser examples) as it seems strange to me that you would use pure sql when the whole idea of EF is abstracting that away. I have tried to use the context in the UP method but for some reason it didn't think that a table that was created in the migration existed when I tried to add the seed data directly below the call to create the table.
Any wisdom greatly appreciated.
If you want to use entities to seed data you should use Seed method in your migrations configuration. If you generate fresh project Enable-Migrations you will get this configuration class:
internal sealed class Configuration : DbMigrationsConfiguration<YourContext>
{
public Configuration()
{
AutomaticMigrationsEnabled = false;
}
protected override void Seed(CFMigrationsWithNoMagic.BlogContext context)
{
// This method will be called after migrating to the latest version.
// You can use the DbSet<T>.AddOrUpdate() helper extension method
// to avoid creating duplicate seed data. E.g.
//
// context.People.AddOrUpdate(
// p => p.FullName,
// new Person { FullName = "Andrew Peters" },
// new Person { FullName = "Brice Lambson" },
// new Person { FullName = "Rowan Miller" }
// );
//
}
}
The way how migrations seed data are not very efficient because it is supposed to be used for some very basic seeding. Every update to new version will go through whole set and try to update existing data or insert new data. If you don't use AddOrUpdate extension method you must manually ensure that data are seeded to database only if they are not present yet.
If you want efficient way for seeding because you must seed o lot of data you will get better result with common:
public partial class SomeMigration : DbMigration
{
public override void Up()
{
...
Sql("UPDATE ...");
Sql("INSERT ...");
}
public override void Down()
{
...
}
}
I wouldn't recommend using Sql() calls in your Up() method because (IMO) this is really intended for actual migration code for which there is no built-in function, rather than seed code.
I like to think of seed data as something that could change in the future (even if my schema does not), so I simply write "defensive" checks around all of my inserts in the seed function to make sure that the operation did not fire previously.
Consider a scenario where you have a "Types" table that starts out with 3 entries, but then you later add a 4th. You shouldn't need a "migration" to address this.
Using Seed() also gives you a full context to work with, which is a lot nicer than using the plain sql strings in the Sql() method that Ladislav demonstrated.
Also, keep in mind that the benefit of using built-in EF methods for both the migration code and seed code is that your database operations remain platform-neutral. This means your schema changes and queries are be able to run on Oracle, Postgre, etc. If you write actual raw SQL then you are potentially locking yourself in unnecessarily.
You might be less concerned about this since 90% of people using EF will only ever hit SQL Server, but I'm just throwing it out there to give you a different perspective on the solution.