I'm trying to find out what is the semantic of System.Data.Entity.Migrations.Infrastructure.IMigrationMetadata interface in the EF. I know that it's used to manage and apply DB migrations. But I can't find detailed information about it. To be specific I would like to know:
- What Source property is used for? Why it's always null when I generate migrations using tools?
- What Target property is used for? I see that tools is generating something Base64-looking and placed into resources. What is it? Why it's generated in such non-friendly format?
- Is it possible to develop migration manually without tools usage? I suppose it is not easy because of that Target property Base64-like value which should be generated somehow. Am I right?
- When this interface is actually used? At the moment I found out that migrations not implementing this interface can't be found automatically by migrator. Am I right? Is it the only purpose of the interface?
You go to: EF6 repository on codeplex and you see:
You can get the project and check references to see how this interface is being used. The base64 thing is your model. Again with the code you should be able to track how it is done.
The IMigrationMetadata Interface has the following responsibilities that I know of.
Update-Database
.I am guessing that the Source property is often not implemented by the tooling as it is not required in the implementation of
Add-Migration
. That code probably just compares the model as it was at the end of the most recent, existing migration with a model generated from the code to determine the changes that need to be included in the new migration.The Target property returns a model in EDMX format that has been both compressed using the GZipStream and encoded using Convert.ToBase64String. I wrote the following code to both decode and encode these values. You would probaly find this useful if you are going to be coding migrations manually.
The compression probably explains your query as to why a non-human readable format was chosen. This content is repeated at least once (in the Target property) for each migration and can be large depending on the size of the model. The compression saves on space.
On that note, as far as I can see, it is really only the last migration that is required to return a true representation of the model after it has been applied. Only that migration is used by
Add-Migration
to calculate the changes required in the new migration. If you are dealing with a very large model and/or a very large number of migrations, removing that content could be advantageous. The remainder of this post covers my derivation of a minimal value for the Target property which can be used in all but the most recent migration.The Target property must return a string object - an ArgumentNullException is thrown in a call to System.Convert.FromBase64String in System.Data.Entity.Migrations.DbMigrator.ApplyMigration when update-database is called if Target returns null.
Further, it must be a valid XML document. When I returned an empty string from Target I got an XmlException with the message "Root element is missing.".
From this point on, I used my code from above to encode the values.
I did not get very far with gradually building up the model starting with
<root />
for example so I swapped over to discarding elements from an empty EDMX file that I generated by adding a new 'ADO.Net Entity Data Model' to my project and then choosing the 'Empty Model' option. This was the result.When I encoded this using my code from above, this was the result.
Be careful to ensure that you retain the real Target values for each of your migrations in source control in case you need to roll back to an earlier version. You could try applying the migration to a database and then using Visual Studio to generate an EDMX file. Another alternative would be to roll back the classes that form your model and then execute
Add-Migration
. Take the Target value from the newly created migration.