Handling code-first database migrations that fail halfway - c#

My company has tasked me with figuring out if we want to use EF6 for some new applications. I've done some testing, and I get the general idea of most aspects, but the database updates generated by code-first migrations worry me.
I have a database with 3 tables. A 4th was added, and the 3 existing tables received a foreign key to this table. I generated an update script and ran it. But I made a mistake. This happened:
The new table was generated.
The foreign key was added to the first existing table.
The second table had existing data, and I forgot to specify a default value for the foreign key, so the update failed at this point.
I now have a partially updated database, which to me is a Really Bad Thing. The EF6 system has no idea at this point what it did and did not execute, and if I somehow lose the migration error, neither do I. The only way I could find to fix this was:
Figure out which update statement cause the error.
Manually undo the changes in the database that were executed before the faulty statement was hit .
Run the migration again and hope I got it right this time.
Manually fixing the database was relatively easy, since I only added things. If the migration had for example removed some columns, it would have been way more difficult to revert the changes. Furthermore, a migration like this could very well run without trouble on a development machine that has no data in its tables and suddenly fail when deploying to a testing environment (or worse).
If we are going to use this framework, we need to be sure that there's no way that anyone can accidentally corrupt a database. So my question is: how do people handle issues like these with EF6? Should I just always use the -Script parameter to run the updates manually one by one? Do I just suck it up and triple check all migrations? Is there a better way to deal with this?
I hope the question is clear and I'm looking forward to any insight.

Related

Mistake in an EF Migration better to rollback, delete, re-add or just simply add new

I created a large migration that creates my initial schema and ran database update.
Afterwards I noticed that a field that is supposed to be of type DateTime is accidentally of type string. I fixed it in my model.
Now should I update the database to a migration prior to the one with the mistake, delete the bad migration, then re-add the migration again. Or just simply add a new migration that only patches the fix.
The reason I am leaning towards rolling back, deleting, then re-adding is because I wouldn't want any messed up migrations with incorrect info would I? I feel like it is pointless to have migrations that are incorrect.
I believe the confusion comes in for me because I have never used migrations in a production environment so I don't think I am aware of the power of them. So I would like someone to clear up whether old migrations can have mistakes or if they should all be free of mistakes and show the entire progress of the database as I add new models / entities.
Migrations are just a tool to help you preserve data between schema changes. They're especially handy for managing multiple database servers like dev/test/production or dev-local databases in team environments.
If you only have one server, then rewriting a migration is cheap, so go ahead and correct it this way.
If everyone on your team has already applied the migration, or you've applied it to databases with data you would like to preserve, then it would be simpler to update the column using a new migration.
In other words, there is no right or wrong way to use Migrations, only a cost associated with rewriting history.

There is already an object named 'TableName' in the database. - a different solution

This is not really a question (yet!) but rather sharing something that happened to me last night and the solution was completely different from those found on stackoverflow or google.
After adding some new functionality to an existing application which resulted on a couple of changes on the model I deployed the application to our development environment without an issue. However, when I deployed it to our production environment I started getting this "There is already an object named 'TableName' in the database." error.
Clearly, Entity Framework was trying to (re)create my model from scratch instead of updating it. After trying several solutions including the Global.asax SetInitializer(null), resetting migrations, etc. nothing worked and would only lead to other errors.
At some point I just rolled all of my attempts to fix changes back and started from scratch looking for a solution.
The solution was actually to go into the very first Migrations file (typically called init or Initial) and comment out the code that was trying to create the tables.
Afterwards, I could see that there was another migration trying to dropfield also generating an equally ugly error (something along the lines of "Unable to remove field 'FieldName' because it doesn't exist"), so I had to comment that line as well.
So basically, after commenting out a few migration lines, everything started working and the model did get upgraded to the latest version.
Now, here's the question.
Clearly, Dev and Prd were out of sync DB-wise (which is fine, to my eyes) but this ended up creating migrations that, for some reason, were not compatible with production and this is where I cannot understand how Entity Framework is not able to manage this. I mean, why was EF trying to create a table if it already existed? And why was EF trying to drop a field that was not present in the table schema?
Is this something not covered by EF? Or did something happened at some point that messed up the entire EF set up of my project?

Not using code first migrations

I love code first. But here and then facing contraint problems and such , that makes me drop database and recreate etc.
My concern is that, once in production, i cant do that.
Is it possible not to use code first migrations and just creating fields by hand at database/tables?
That also makes me worry for foreign key constraints again.
What is the best way to do this?
If you use EF < 4.3 you can recreate database on dev server and manual update production database in two step:
creating fields by hand at tables
update EdmMetadata table (use data form dev database)
Else use code first migrations : update-database -script,
This command generate update script for you database, and you can do it manually.
At about 4:20, the tutorial video at the Microsoft website starts talking about Migrations
http://msdn.microsoft.com/en-us/data/jj193542.aspx

How to force EF code first to recreate databases?

I had a bunch of tables Code First created.
Then in SQL i deleted one table so that i could inevitably ask this question on stack.
Upon using update-database in package management console I get:
Cannot find the object "dbo.ContractParents" because it does not exist
or you do not have permissions.
What is the best way to recreate my table?
I've read up about context.Database.CreateIfNotExists();
I put it in my seed function, but nothing doing.
Thanks!
To explain what happens with your update-database command and why the context.Database.CreateIfNotExists() method in the seed did not work:
When you run the update-database command it first looks at your connection string to see if the database is there. If it is it looks at the migration history table and checks that against what is in you DbContext class. If it sees that there are tables missing or changes it will attempt to update the database. The Seed method is not called until after that is done, so that is why that did not work.
While developing using EF-Code First I usually approach the problem in a few different ways depending on how large my database is. I usually went the route of deleting all the tables (including the migration history table) and then running the update-database command again. Works fine, just really time consuming if you have a lot of tables with a lot of FK constraints on it.
I finally became tired of it and found these scripts to make the dropping of tables exponentially faster. I went to this because I was running my app on Azure. When I am running it on my local machine, I would just delete the whole database and make a brand new database with the same name.
Elegant solution? No.
Does it work? More or less...
For yet another cheesy option...
Right click on your db in server explorer, and hit delete
Then you can do
Enable-Migrations -EnableAutomaticMigrations -Force
Update-Database -Force
Dirty update, clean result :)
For a quick and dirty approach, that'll get you home for dinner on time along with lots of dataloss (i'm still in beta using test data)
drop the dbo.__MigrationHistory system table
along with all of your other tables.
Back up your data first!
update-database -verbose (you may need some sauce with your spaghetti)
I am not impressed, but it works.
Hopefully someone will come up with a better answer in the future.
It would help to really understand migrations better.

Resetting Context for Entity Framework 5 so it thinks its working with a initialised Database - Code First

Linked to this question:
Cannot Split Table with EF 5 - Code First - with existing database
But i think the answer to that question is actually not a problem with code first but with something i did whilst developing.
The scenario is this:
Had an existing database and used this to begin creating my data context
Began working with it but soon realised that naming conventions were poor and some tables needed remodelling.
Decided to create a new database with better conventions for existing tables taken across and remodelled the new bits
Updated the context to look at new Database
Even though migrations where not enabled, i was getting errors with the database being out of sync (even though up until this morning it was still pulling data)
I enabled migrations (comment in other question) and output to script. And you can see the sync changes are things like table names and Id properties etc.
I can't move forwards, the context seems does not like it when you switch databases on it like this (which i get to a point but this is really brittle). What i need to do somehow reset the context so it doesn't actually think any changes have been made to the database and it thinks it is working with an initial database again.
I have deleted the migrations folder, but that does nothing. Is there a any sort of way i can get this to happen?
Try deleting the __MigrationHistory table in the database. It's a system one.

Categories

Resources