Codefirst and migrations - entity-framework

When an application is Live an iterative approach to database changes is obviously required. In the db first world I would change the object (eg. column added to table) in the databaae project, then deploy (recreate) to my local instance, then replace the old table with the new in my edmx - when it was go Live time a delta script is generated out of the database project compared to a copy of the Live database schema. Sounds long winded but at the end of the day I only made the change once (the object in the db project) - everything else is generated
Flip over to code first (EF6) and Im expecting a similar one change experience - i.e. I add the property to the class - however do I additionally need to add a migration script ?
I've been reading and it seems many advise to disable migrations to have more control - I'm confused - I had visions of simply deploying the app and the changes automatically reflected in the target database the next time the app runs - one thing is for sure I don't want to manually write separate deployment scripts (or migration code). As mentioned I'm confused about this final part - can anyone clarify - point out the options
Many thanks

Short answer is there's no need to create a 'migration script', you're correct as EF will handle it for you if you want. I think when you read about disabling migrations, you were probably actually reading 'disable automatic migrations'; EF will still generate migrations regardless.
As you pointed out it IS a two-change process when developing: First you change your class, then you open up the Package Manager console and call Add-Migration. Usually, that's all you have to do, and EF will generate the change code for you. Then, you call Update-Database and it does it's work. When you go to deploy, you will connect to your target database and call Update-Database once and it will apply all migrations that are pending.
You can also enable auto-migrations which skips the Add-Migration step, but I always like to review the generated code. Call me old-fashioned ;)
It gets more complicated when you need support for views, SPROCS, and UDFs, but there are ways to do most anything you want to do. And, even though it's a 2 (3?) step process to get changes out to the DB, it's still much easier than changing the DB and code separately, by yourself.
Then, you can follow the steps here to set your deployment up so that once your EF is initialized on a connection to your production DB, it automatically applies the updates. Again, I would advise to do it yourself (via the package manager console) just to be safe but it's not necessary.

Related

EF Core Migrations manual edits possible?

I am using EF Core 2.0 in my sample project with some value object configurations. I modify the code and generate migrations via CLI command line. In the last migration rather than adding a new database table as it should, it is trying to rename existing tables to each other and create an extra table for existing one. I could not figure out the reason for it.
Issue is, since with EF Core the snapshot is a separate auto-generated file from the migration itself I don't want to modify the snapshot.
I only want to modify the migration script so that it will not rename multiple tables, and then generate the snapshot from the migrations I created.
I did not see any command for this in the CLI - is it such a bad practice to modify the scaffolded migration and regenerate or am I missing some obvious new link where how to manually modify migration scripts is explained?
Thanks a bunch.
Update 1: After comments, added info about the snapshot from this link.
Because the current database schema is represented in code, EF Core doesn't have to interact with the database to create migrations. When you add a migration, EF determines what changed by comparing the data model to the snapshot file. EF interacts with the database only when it has to update the database. +
I examined my generated snapshot code from source control. It exactly has added one extra table as what I needed.
The migration script to generate this is hectic at best - renaming multiple tables to each other and then warning that this could break causing multiple issues.
Since this is a sample project for me with only mock data as of now at least, I decided to go for it and not break the automated scripts. I am willing to lose some mock data at this stage rather than wasting time on it.
If this were in a production database I would be extremely careful to manually create the same result with intervention modifying both the scaffold and the migration file.
I am accepting this one as an answer (basically saying current EF Core does not support it to the best of my current knowledge) since there is no other candidate now - I will be more than glad to accept if any better answer shows up.

Strategy for deploying EF controlled Database

I have written an application using EF 6.0 in combination with an SQL Server Compact 4.0 Database. When a customer uses this application for the first time, it (the application) should create a database-file in a given path with some initital values. Also migrations should be allowed, for it is quite possible that the object model might change with future versions of the app.
Now I´m wondering what would be the best way to to deploy the DB on the users productive system. I could think of three ways:
I could create a DB-file with initial values and just copy it to the right place during installation process and use MigrateDatabaseToLatestVersionInitializer in the app.
In the DbContext-Constructors (I have two contexts) I could check for an existing DB-file and use different Database-Initializers accordingly. Like a CreateDatabaseIfNotExistsInitializer with a seed method that creates initial data if no fiel is found and a MigrateDatabaseToLatestVersionInitializer if the DB-file exists.
I could use the MigrateDatabaseToLatestVersionInitializer always and in its "Seed"-method check for existing table entries and create them if they are not present.
Which of these ways is to be preferred or is there a better way I didn´t think of?
It sounds like this is a desktop application so you might want to catch permissions errors about creating the database file at installation time (i.e. option 1) rather than run time, especially as in option 2 the database initialization is not an imperative command you're giving that you can put a try...catch around.
I don't think option 3 would work as the Seed method gets run after all the migrations, so surely the migrations will either have successfully run, in which case the tables don't need creating, or they will have failed as the DB doesn't exist and therefore your Seed method won't get run.

Entity Framework 5 Code First - How to "start over"?

I've been using EF 5 Code First, successfully, in my app. I have roughly 40 tables. However, I've run into an issue that I can seem to get Migrations to handle correctly. So, what I would like to do is to somehow tell EF to treat the current schema of the database as a new starting point, and start managing it from this point. This way, I can make the necessary schema change manually, and then tell EF to essentially start over from this point.
Is there a way I can do this? I presume I'm going to have to delete the __MigrationHistory table, or remove its contents. But I'm not sure how best to proceed with doing this.
You should be able to do the following:
Change your database manually to reflect the changes in the model that wont be handled by a migration. Everything should work now, but the database and the migration system are out of sync.
Run Add-Migration ManuallyUpdatedDatabase -IgnoreChanges. This creates a migration that is completely empty, so it wont make any changes to the database, but it will make sure that the system knows about the manual changes that have been made. That way the manual changes wont be included in the next migration you create.
Run Update-Database to apply the empty migration.
From here on everything should work as usual. You just have a "missing link" in your migrations because you have handled some changes manually.

EF Code first automatic migration totally messed up

I'm not sure what I've done, but I get this error when publishing to azure:
Automatic migration was not applied because it would result in data loss.
Now this is very distubing. My models match my database 100% - so is there a chance there might be data loss if I force it? I'm really confused what to do now.
So much for auto migrations :S Not much automation :)
I think my error was that I created new models, published it and EF created new tables for them. I then remembered that I forgot do add the models to my DbContext. So I added the new DbSets to context and published. That's probably where it went wrong. But then again, I didn't know that EF added models to the database if they aren't POCO classes or what ever they are called. Might have been some foreign keys that triggered.. dunno. Anyways I went undo frenzy on my code and deleted all the newly created tables and stuff to get me to my starting point. I thought that might solve it. But noooee stupid me.
Any ideas where to start on this issue? Im gonna jump off a cliff I lose my data :)
You can have EF create the SQL for you, so you can implement the migration manually. In the package manager console enter:
update-database -v -f -script
It will open a new window with the SQL that you can look over, and then apply yourself directly to the database. The last line that enters an entry into the migration history will allow the DbContext to know it's looking at the correct version.
First make a backup! Especially easy if you're using SQL Compact - just copy the file.
Or with LocalDB or SQL Server, Detach, copy file, Attach..
But to give a little more help, generating that script might still have you look for what might cause data loss. I find that adding a new column to become primary key in a table might loose data even if the original column is kept, because of a NOT NULL constraint being enforced on the new column causing (all) rows to be dropped.

Code First Migrations for dynamically assembled model

My database model (sometimes referred to as "context") is dynamically assembled at startup based on which services and/or plugins are installed. Plugins and services export their model definition fragments through my IoC container and the application core picks them up and runs them when the DbContext.OnModelCreating method is called.
The question is: Can I (and how do I) use Code First Migrations with this setup?
(below is more information on what I've tried and what particular problems are)
In my previous project, the database was inherited from some old code so we couldn't use any of the Code First database generation stuff anyway. We simply kept a long line of delta scripts and executed them manually on deploy (it was a single-host kind of project).
Now I'm starting a new project, and this time, the database is brand new, ready for Code First to play with. Initially, I was all excited about Code First Migrations, seemed like the way to go. Until I actually tried it. The initial attempt, quite obviously, failed due to the absence of an explicitly defined DbContext in my project.
So far, it looks like the only viable option is to manually code migrations, with which I am perfectly fine. However, it turns out that this is not as simple as just creating a few classes inherited from DbMigration.
After some experimentation on a small test project, I was able to find out that the migration autogenerator adds an implementation of IMigrationMetadata, which, among other things, contains a hash of my model as the values of the Source and Target properties. Presumably, this hash is then used to identify a path across migrations from the "current" state of the database (as recorded in the __MigrationHistory table) to the newest state as defined by the model in code. This totally makes sense, but...
Naturally, I have no idea where to get that hash for my model, which makes me unable to implement IMigrationMetadata on my migrations.
On the other hand, I see that the metadata interface is not included in the DbMigration class itself, which makes me think that it might be optional. It then follows that migrations can actually work without the hash values, but the question is - how?
All the information I could find on the internet is just simple, very basic tutorials. No information on how to create migrations manually (and whether it's even supported). No documentation on how it actually works and how to extend it. And it is not quite obvious from outside.
I am ready to resort to ILSpy at this point, but the whole EF is so complex that I fear I may not be able to find what I need in reasonable time.
Here are a few ideas that you could pull together to find a solution that works for you. I realize I mentioned some of these in our other thread, but I'm including them here for others reading this question.
Automatic migrations allow Code First to automatically calculate and apply changes to the database.
You can write your own code to generate and apply migrations. I've written a post about applying migrations and the MigrationsScaffolder class will help you create migrations.
When you run the project , an extra table is created in the database.
EdmMetadata table
The hash is always created with the help of EdmMetadata Entity and the current code first model. It is SHA-256 hash stored in the EdmMetadata table of the database. You can get it from that table.
Methodology to be followed will be:
Get the hash of the current model using
var hash=GetModelHash(OldContext);
Check whether the model in the code (new model) is compatible with the model in database(old model) using
CompatibleWithModel(hash,CurrentContext,ObjectContext)
This method returns bool.
If it is not compatible, then delete the existing tables in the database.
Create new tables
Save the current hash to the databse
Seed the data.
The code may look like:
{
var objectContext = ((IObjectContextAdapter)context).ObjectContext;
var modelHash = GetModelHash(objectContext);
if (CompatibleWithModel(modelHash, context, objectContext))
return;
DeleteExistingTables(objectContext);
CreateTables(objectContext);
SaveModelHashToDatabase(context, modelHash, objectContext);
SeedData(context);
}
Be sure to make the class inherited from
IDatabaseInitializer<T> where T:DbContext