NOTE. I will call “add-migration” for each migration created using Add-Migration , or automatically created using automatic migrations
NOTE: when I say “DbContext state”, I mean the definition of the model made in the code first, that is, entities, their properties, relationships and all other configurations
NOTE. "Known DbContext" means all types of database objects that DbContext knows about, such as tables or views mapped to objects. There are many other things in the database that DbContext does not know about, including tables and views that are not mapped to DbContext objects
I hope I understand the basic workflow. First I create a model, then I create an initial migration, and I generate SQL from this, OK. I update the model, I create a new migration from it and a new SQL from it, OK.
Of course, you can change the database schema from one added migration to another added-migration, regardless of whether it is updated or reduced, or how many added migrations are between them. That is, you can specify the source and target migrations.
Do I think this is a one-way workflow?
If this means that you can only apply migrations from code to the database, yes, this is only from code to the database, and there is no other way.
If I change the migration class incorrectly, it will never be reflected in my model,
Why are you doing it? Migrations were created only to do this flawlessly, without making mistakes. Why do it manually? Added migration includes defining a process for updating from a DbContext state of a previously added migration to the current DbContext state. And to lower the process, i.e. Return to the DbContext state of the previously added migration. If you are not careful when changing migrations, you can break it.
and if the database schema is not exactly what it should be, EF will never notice, and I will get only strange exceptions, right?
Nope! it has nothing to do with migrations. Regardless of migrations, when DbContext is installed, the model is created in memory and checked against the DB schema. If this does not match, you will get an exception. But this has nothing to do with migrations.
Usually you change your model, add hyphenation and apply the transition to the database to synchronize the DbContext and DB schema. Another option is to modify the database and use the T4 template to reverse engineer the database and get the DbContext from the database schema. The question is, both should be synchronized, but no matter how you do it.
How to be sure that when I change the migration class, I do not cause inconsistencies? I assume that I can only do two things: firstly, add new database objects that EF does not care about, and secondly, change the migration code with the EF code so that it ends with the same scheme (for example, if EF generates a drop column and an add column, I can change this to a rename column), and the Down () and Up () methods must be consistent, is that all? For example, can I ever change the circuit that EF cares about?
Do not mix DB schemas, DbContext, and migration concepts.
As stated above, DB and DbContext must be synchronized.
Migrations are an easy way to achieve this synchronization: you create the original model and add the first migration added. Then you create a database. DbContext and DB schemas are perfectly synchronized. What happens if you change the migration so that the database schema changes and does not match the DbContext? Your DbContext and your database schema would be different, and an exception would be thrown when creating the DbContext.
But then, why is there a migration table in the database?
When you apply migration to the database, the database schema and snapshot of the current schema (or rather, part of the schema known to "DbContext", and not the entire database schema) are __MigrationHistory and stored in the Model column of the __MigrationHistory table in the database.
Migrations know how to change the database schema from an added “source” migration to a “target” added-migration. The migration history table is used to verify that the database schema matches the last applied migration. That is, before applying the new migration, the migration checks that the current database schema matches the scheme when the last migration was applied using the snapshot stored in the migration table. If this does not match, the process will fail. If it matches, the transfer will safely apply the changes from the "added-source" migration to the "target" added migration and save a snapshot of the resulting schema.
So how can you break things?
- by changing the migration code so that it does not correspond to changes in the DbContext (for example, adding a new column to the migration and not adding it to the DbContext object).
- by changing the database in a way that makes the database schema different from the snapshot taken when applying the last migration (therefore, 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 does not change the database schema "known" by DbContext, i.e.
- adding objects (even tables) that are not "known" DbContext defined in the code (and, of course, triggers, stored procedures, views ...)
- adding or deleting data (rows from tables), for example, filling in the main tables
- performing any other actions that do not change the circuit (changing security, configuration, etc.)