Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Entity Framework: am I supposed to modify migration classes?

I hope I understand the basic workflow. First I create a model, then I generate an initial migration, and I generate an SQL from that, OK. I update the model, I create a new migration from that, and a new SQL from that, OK.

Am I correct in assuming that this is a one-way only workflow? If I change the migration class in a bad way, it will not ever be reflected in my model, and if the database schema is not exactly what it should be, EF will never notice, and I will only get weird exceptions, right?

How to be sure that when I modify a migration class, I do not cause inconsistencies? I assume I can only do two things: first, add new database objects which EF doesn't care about, second, change EF-generated migration code in a way that it ends up with the same schema (for example, if EF generates a drop column and an add column, I can change that to a rename column), and the Down() and Up() methods have to be consistent, is that all? For example, can I ever change the schema that EF cares about?

like image 824
fejesjoco Avatar asked May 30 '14 14:05

fejesjoco


People also ask

How does migration work in Entity Framework?

EF Core compares the current model against a snapshot of the old model to determine the differences, and generates migration source files; the files can be tracked in your project's source control like any other source file. Once a new migration has been generated, it can be applied to a database in various ways.

Should EF migrations be committed?

Definitely the migrations should be committed in source control. Deleting migrations will make it impossible for EF to generate future migrations for future changes to an existing database.

Can I use EF core without migration?

Hi @PanagiotisKanavos, as you mentioned, it does not require migration.

What does remove migration do?

Remove a migrationTo remove the last migration, use this command. After removing the migration, you can make the additional model changes and add it again. Avoid removing any migrations which have already been applied to production databases.


1 Answers

NOTE: I'll call "added-migration" to every migration created with Add-Migration, or automatically created by automatic migrations

NOTE: when I say "state of DbContext" I mean the definition of the model done in code first, i.e. the entities, their properties, relations and all other configuration

NOTE: "known by the DbContext" means all kind of database objects which the DbContext is aware of, like tables or views mapped to entities. There are a lot of other things in the DB that the DbContext is not aware of, including tables and views not mapped to DbContext entities

I hope I understand the basic workflow. First I create a model, then I generate an initial migration, and I generate an SQL from that, OK. I update the model, I create a new migration from that, and a new SQL from that, OK.

Of course, and you can change the DB schema from one added-migration to other added-migration, no matter if it's an upgrade or downgrade, or how many added-migrations are in between. I.e. you can specify source and target migrations.

Am I correct in assuming that this is a one-way only workflow?

If this means that you can only apply migrations from code to DB, yes, it's only from code to DB, and no the other way.

If I change the migration class in a bad way, it will not ever be reflected in my model,

Why would you do so? Migrations have been created just for doing it flawlessly without making mistakes. Why doing it by hand? An added-migration includes the definition of the process to upgrade from the DbContext state of a previously added-migration to the current DbContext state. And the process to downgrade, i.e. to go back to the DbContext state of a previously added-migration. If you're not careful when modifying the migrations, you can break this.

and if the database schema is not exactly what it should be, EF will never notice, and I will only get weird exceptions, right?

Nope! it has nothing to do with migrations. Independently of migrations, when a DbContext is instanced, the model is created in memory, and checked against the DB schema. If it doesn't match, you'll get an exception. But this has nothing to do with migrations.

You usually modify your model, add a migration, and apply the migration to the DB, so that the DbContext and the DB schema are synchronized. Other option is to modify the DB and use a T4 template to reverse engineer the DB and obtain a DbContext from the DB schema. The question is that both must be synched, but it doesn't matter how you do it.

How to be sure that when I modify a migration class, I do not cause inconsistencies? I assume I can only do two things: first, add new database objects which EF doesn't care about, second, change EF-generated migration code in a way that it ends up with the same schema (for example, if EF generates a drop column and an add column, I can change that to a rename column), and the Down() and Up() methods have to be consistent, is that all? For example, can I ever change the schema that EF cares about?

Don't mix up DB schema, DbContext and migrations concepts.

As stated above, DB and DbContext must be synchronized.

An migrations are an easy way to achieve this synchronization: you create the initial model and add the first added-migration. Then you create the DB. The DbContext and the DB schema are perfectly synchronized. What would happen if you modified the migration in a way that the DB schema changed and didn't match the DbContext? Your DbContext and your DB schema would be different, and an exception would be thrown when instancing the DbContext.

But then, why is there a migrations table on the DB?

When you apply a migration to the DB, the schema of the DB is updated, and an snapshot of the current schema (more precisely, of the part of the schema "known" by the DbContext, not of the whole DB Schema) is taken, and stored in the Model column of __MigrationHistory table in the database.

Migrations knows how to change the DB schema from a "source" added-migration to a "target" added-migration. The migration history table is used to verify that the DB schema is consistent with the last applied migration. I.e. before applying a new migration, migrations verifies that he current DB schema matches the schema when the last migration was applied by using the snapshot stored in the migrations table. If it doesn't match, the process will fail. If it matches, the migration will safely apply the changes from the "source" added-migration to the "target" added-migration, and store the snapshot of the resulting schema.

So, how can you break things?

  • by modifying the migration code in a way that makes it inconsistent with the DbContext changes (for example, adding a new column in the migrations, and not adding it in the DbContext entity).
  • by modifying the DB in a way that makes the DB schema different to the snapshot taken when applying the last migration (so, when you want to apply a new migration, the real schema and the snapshot will not match, and the process will fail)

What can be done safely?

Anything that doesn't change the schema of the DB "known" by the DbContext, i.e:

  • adding objects (even tables) that are not "known" by the DbContext defined in the code (and of course triggers, stored procedures, views...)
  • adding or removing data (rows from the tables), like populating master tables
  • doing any other thing that doesn't modify the schema (modify security, configuration, etc)
like image 76
JotaBe Avatar answered Oct 31 '22 07:10

JotaBe