How do I use Entity Framework in Code First Drop-Create mode? - entity-framework

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>

Related

Is there a way to query the database before or during OnModelCreating?

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. :)

How to execute seed step using migration.exe on existing database?

I have someone else's ASP.NET application that uses code-first EF and comes with the code for database migration and seed. I usually run migration.exe before the new version of the app gets installed and it worked well as long as I let EF do everything starting from creating a brand new database. Now I have to make it work against an existing and EMPTY database. When I run migration.exe it doesn't return any errors and perform all the required migration steps but it not longer runs seed step (it probably assumes it's not needed since the database already exists). How do I force running seed step in this case?
There are steps you need to ensure are set for your database initialization to achieve what you want:
CreateDatabaseIfNotExists: This is default initializer. As the name suggests, it will create the database if none exists as per the configuration. However, if you change the model class and then run the application with this initializer, then it will throw an exception.
DropCreateDatabaseIfModelChanges: This initializer drops an existing database and creates a new database, if your model classes (entity classes) have been changed. So you don't have to worry about maintaining your database schema, when your model classes change.
DropCreateDatabaseAlways: As the name suggests, this initializer drops an existing database every time you run the application, irrespective of whether your model classes have changed or not. This will be useful, when you want fresh database, every time you run the application, like while you are developing the application.
Custom DB Initializer: You can also create your own custom initializer, if any of the above doesn't satisfy your requirements or you want to do some other process that initializes the database using the above initializer.
The best help guide I followed with getting started on understanding Code first was written here and references the part you are referring to:
http://www.entityframeworktutorial.net/code-first/database-initialization-strategy-in-code-first.aspx
The important thing though is to know that you may want different things for different environments too and may wish to get into understanding how to do different deployments for different environments.
An example of a custom one would be like this:
public class EasyContext : DbContext
{
public EasyContext() : base("name=EasyEntity")
{
Database.SetInitializer<EasyContext>(new EasyInitializer());
}
public DbSet<Person> Person { get; set; }
}
You should be setting a breakpoint to make sure it is being caught or else you can force a new configuration to fire as well.

EF codefirst migrations how it works in a production environment

I am a newbie in Codefirst and I do not understand how it works correctly.
I created 3 migrations, migration 1..3 via "Add-Migration" command and issued the relative update with "Update Database".
I have a Configuration.cs file in my Migration directory and custom database initializer (I am working on MySQL) I created in order to seed initial data.
I do not know what happens behind the scenes in the production environment where I do not have any database yet.
Who is responsible to create and update the database? Are the migrations executed one after the other?
Can you suggest me how this process works in production and share useful links?
Regards,
Roberto
Assuming you are using Automatic Migrations - All migrations are called one after another, in the sequence in which they were created. Their Up function is called. Afterwards the Seed function on your Configuration class should fire.
Each migration has a sort of a Time-Stamp inside its file name, like this:
if you are creating lots of databases out of a single context class like I do, and you are afraid of not having control over migrations, you can use manual migrations. It is called DbMigrator.
See my/others answer here how to use it.

Best way to incrementally seed data in Entity Framework 4.3

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.

Manually editing database in code first entity framework

I have been trying out EF 4.1 (code first) with MVC 3. I am thinking ahead to when the application will need changes. I tested a couple of scenarios. I like the idea of manually editing the database when the model (my POCOs) would changed.
ASP.NET error when I change the model :
"The model backing the 'CTCMContext' context has changed since the database was created. Either manually delete/update the database..."
Now, it says that I can "manually update the database", but I did and still get the same error. Am I missing something !!?!
EDIT
Does this have to do with the model hash generate by EF ?
I have had some struggles with this as well. I found that when you let EF create your database for you that a table named dbo.EdmMetadata is created and this is where/how EF tracks the state of the model. I found that if you delete this table after the database has been initially created you will put things into "manual mode" where you can now manually add/remove columns, tables, etc. from your database and EF will not throw the error that you are seeing.
If however you want to keep having EF update your database as you make changes to your model, you will need to create and call a ContextInitializer class that inherits from either DropCreateDatabaseIfModelChanges or DropCreateDatabaseAlways depending upon the behavior that you want to have happen.
change the class with the new fieldnames, delete the table "EdmMetaData" then recompile your app.
You will be responsible on modifying the fieldname on your views.
it works for me.
As I can see, there aren't really any methods built-in EF for code-first data evolution.
For what was of my initial question, the answer lies in removing the schema generation/validation. It is only then that manually editing the code and database may work.
UPDATE :
EF 5.0 now support migrations
I know this has been marked as solved but in my case it didn't do the trick.
Once I deleted dbo.EdmMetadata I was getting a different error:
Model compatibility cannot be checked because the database does not contain model metadata. Ensure that IncludeMetadataConvention has been added to the DbModelBuilder conventions.
The way it worked for me was to remove the Initializer class from Application_Start:
void Application_Start(object sender, EventArgs e)
{
// MyDB.SetInitializer<MyContext>(new MyInitializer());
}