I've been using Entity Framework migrations for some time and I started wondering how they actually work under the hood. I mean the following:
How does EF understand that the model in the application and the db scheme are different? As far as I know, there's a table __MigrationHistory in the database where all migrations are stored as well as in the Migrations folder in the application (applies only to code-based migrations). In the __MigrationHistory table, there's a column called model which contains some kinda hash. What is that hash exactly? Is it a snapshot of the model? Is it the changes that EF needs to apply to get from the previous migration to this one?
If it was the model snapshot, it would mean EF would have to figure out how to transform the current model to the snapshot each time we decided to update database.
However, if it was the changes, it would mean EF would have to apply those changes to the current model in order to understand when the db model and the application model are different.
The question is, where can I read something about how the migrations are implemented and what is this model column in the database. I would appreciate any advices or links.
Update:
I've checked the resources provided and as I've found out, the model column is actually the snapshot of the model. That means, when I run the update-database command, EF goes to the db, checks the latest migration model by decoding the XML string and if the current model in the application and the model EF got from the db are different, EF generates a script to update the db. However, I still don't know what EF does when there are multiple migrations pending.
I will describe on example based on the example from the https://channel9.msdn.com/Blogs/EF/Migrations-Under-the-Hood. Say, we have First migration in your db, then Second migration, which adds the Url column and the Third one, which drops this column. If I were to apply these changes to the db which contains the schema similar to First, would EF add the column and then drop it according to the Second and Third, or will it try to calculate the general changes that are required to update the db and then execute the generated script (in the example case it would do nothing?
Also, there's another link I've found if anyone's interested
https://msdn.microsoft.com/en-us/data/dn481501.aspx
This Channel 9 video covers the general concepts. This blog post might be more specific to your question. In particular, the author concludes on the use of model column (spoiler: its a compressed XML string you can decompress and inspect, has code to do so).
Related
I didn't find any question here that addresses this problem specifically, so here it goes.
I'm using EF Core Code First. One of the tables generated by EF migrations has an additional column that does not exist in my model. It might have existed, as I can see in the ModelSnapshot file, but it was removed a long time ago.
This entity does not have any complex object apart from the identity user and all other properties are primitive. (strings, ints, etc)
I have already tried to add that same field and generated a migration and it appears empty.
Then I tried to remove the field from the model and generated the migration again to see if now it recognizes I am removing it, but again.. migration empty.
I am thinking of removing it from the DB manually but the problem is that it still exists in the model snapshot file, which can generate other sync issues.
I would appreciate any ideas on how to solve this. Thank you very much.
I have reverse engineered on existing database for code first. Next i Enabled-Migrating for the context (Code based migration). When i create an initial add-migration it works fine and would apply on an empty database.
But my requirement is that i need to use the same database i used for creating the models because of the data it has.
Now the conundrum is how do i implement the code based migrations. My database does not have a migration history table. So, when i run Update-database, it tries to create the existing tables and fails.
How can i capture the current state in the migration history or instruct EF to create the migration history with the current schema as the starting point.
Do i need to turn on the automatic migration for initial setup. Please suggest.
Note: I am using EF 6.
You need to establish a baseline migration of the existing items. So the first migration you create should be:
add-migration Initial -IgnoreChanges
The ignore changes tells EF to just save a snapshot of the current database. Now any subsequent migrations will not include the existing tables (just the changes). This would allow you to continue updating your existing database since EF will see the record in __MigrationHistory or deploy to a new, empty database.
See the under the hood section here.
I've been recently digging into how EF migrations work and I've encountered an issue I could not really understand.
I was reading this article and here's what I saw:
At this stage Developer #2 can run Update-Database which will detect
the new AddRating migration (which hasn’t been applied to Developer
2’s database) and apply it. Now the Rating column is added to the Blogs table and the database is in sync with the model.
What I can't get is how EF determines that it has to apply the changes from the AddRatings migration. As far as I know, the workflow is as follows:
Suppose we have two migrations (with the ids 4 and 5) in the project which have not been applied to the db (say, we got the old version of the db with 1, 2 and 3 migrations applied).
Update Db command is run.
EF goes to the db, looks up the MigrationHistory table and gets the latest migration. Then, EF sees that there are migrations 4 and 5 in the project and since the latest migration in the db is 3, it applies 4 and 5.
However, when I look at the screen from the article, I don't really get it. Here's how I would expect it to go:
There are migrations First, AddUrl and AddReaders in the Dev 2 database.
EF looks up the latest migration in the db - it's the AddReaders.
The latest migration in the project is also AddReaders.
Therefore, no changes have to be applied at all.
There's an issue that the code model and the latest migration model are not the same, but EF is able to apply changes to the db anyway, though producing a warning, as the article says.
The question is, what have I got wrong in my reasoning and how EF understands that even though the latest migration in the db and code is the same, there's another migration that has to be applied.
Also, as far as I've understood, the compressed model in the MigrationHistory serves only when the Add-Migration command is run and has nothing to do with the Update-Database command. Is it so?
When performing an update EF compares the set of migrations from the assembly with the set of migrations from the database and applies to the DB all missing migrations. It doesn't matter whether the missing migrations are at the end of history list or somewhere in the middle.
Migrations are compared by MigrationId so you are right, the compressed model has nothing to do with the Update_Database command.
I am new to Entity Framework 6 Code First and am trying to perform what I thought would be a simple task. I want to create a SQL View and then have an Entity in my database context that I can use to query the view.
I have tried articles such as this but the key difference in my case is that the SQL View is not an existing view coming from another existing database.
I examined the proposition made in this article but it seems like overkill to me that I would need to create some extension methods to do something as simple as create a view/entity combo and use it in my database context.
Am I missing something? I know it would be much easier if I weren't using Code First but please keep in mind it's Code First and I am trying to create a view, not reuse one from an existing database.
Colin and Kevin, Thank you for the link to your answer on the other post and your concise answer. I have used several resources to finally create a queryable entity based on a new SQL view. Just in case anyone else is new to EF 6.0 Code First and is just getting their feet wet, I do have a few steps that will hopefully benefit others in the future.
It may seem obvious to more seasoned Entity Framework developers, but in order to execute the 'Migration' approach you need to disable automatic migrations and actually dive into the guts of the Code First Migrations inner workings. Since automatic migrations is turned on out of the box, I had already created a fairly complex database with seed scripts all relying on automatic migrations and rebuilding the database on every run of my application. This post helped me wipe my migrations history and get to square 1 with automatic migrations turned off (I went with the web.config approach in case you were wondering)
After I had cleared my migrations information, I deleted the mdf from within solution explorer. That guaranteed that I wouldn't run into any problems when running Update-Database (further down the list of steps).
In the Package Manger console, I then executed Add-Migration Initial to generate an "Initial" migration. The result of this was the editable Up and Down methods as described in Colin's answer. I then followed the steps in Colin's answer by commenting out the table create statement (Entity Framework tries to create a table but we really want to create a view and map it to the Entity) and inserting my own view create sql statement at the end of the Up method. It's important to put the create statement after the creation of any tables that it may depend on. I also performed my Seed activities in the Configuration.Seed method instead of in my Context's Seed method. I see how this would be important if you were dealing with multiple migrations. Finally, as Colin suggested I added the table mapping to my context's OnModelCreating event.
The final step in this was to actually apply the migration to the database. In order to do that, in the Package Manager console you execute the Update-Database command. That statement will rebuild the database with the "Initial" migration you created and edited in earlier steps.
It still surprises me that I need to do all of this custom work to create a view and map it to an entity with Code First, but at the end of the day it was helpful in getting me started on migrations as you can only rely on the "automatic migrations" for so long anyways.
You can manually add the sql to create the view to a migration then consume it as per your first link.
The answer in the link provided by Colin does the job.
In case there are lots of views to be created, it can be a good idea to save the view queries in separate files and add them in a resource (.resx) file instead of hard-coding the sql queries in the Migration Up() method.
For e.g.
public override void Up()
{
Sql("ResourceFileName.ResourceName");
}
instead of hard coding like
{
Sql("EXEC ('CREATE View [dbo].[ClientStatistics] AS --etc");
}
I'm learning to use EF Code First Migrations from https://msdn.microsoft.com/en-us/data/jj591621.aspx
Somewhere it said:
Code First Migrations has two primary commands that you are going to
become familiar with.
Add-Migration will scaffold the next migration based on changes you
have made to your model since the last migration was created.
Update-Database will apply any pending migrations to the database.
I don't understand what's Add-Migration doing exactly. To more precise, my problem is with:
since the last migration was created
In order to create a migration, it should pick two database structure to compare.
Obviously, one side is the current structure of models in the code. But what is the other side? The options are:
Populating a database structure by unifying all migrations from initial to the last migration before this?
Comparing it to a database which has the old structure?
Check the code behind files of your migrations - they contain a lot of metadata, including a snapshot of the model from when it was created.
So, when you run Add-Migration the process is approximately this:
Build a model based on your code
Find the previous model from your last migration (if applicable)
Compare the two models
Generate a migration based on the difference
There's a useful article with some information and videos that cover this in more detail.