What are the dangers of using EF Migrations (or any auto-migration framework) in production? - entity-framework-4

I'm considering using Entity Framework 4.3 migrations in a production site. The following is my concern:
If the migration fails for whatever reason, I want all statements
rolled back and the site placed in a down state so no users can use
the site while I try to fix the problem. The only thing is I can't
fall back to executing the scripts by hand against the database since
migration files are compiled in the assembly. I could keep track of
both migration files and sql script files separately but at that point why use
migrations at all.
At work, script files are stored in a SQL folder (that no one can browse to) on the site. Previously run script files are registered in the database. When new script files appear in the folder (and aren't in the database), if a user is an admin, they'll be redirected to a DB portal, else get a site-down-for-maintenance. If we try and fail to execute any scripts from the portal, we grab the new scripts and try to run them manual inside of express studio. This has worked for over a decade. I'm only exploring migrations to see if a better way has arrived. It doesn't feel like it. Please let me know if there's a better way and if it's not Migrations, what is it.

I would definitely not use automatic migrations in a production environment. In fact, I'm too much of a control freak to use automatic migrations at all. I prefer code based migrations to ensure that all databases (developers' own personal, test environment, production) have gone through exactly the same update sequence.
Using code-based migrations where each migration step gets a name, a separate migration script can be generated for use when lifting test and prod environments. Preferably it should be run on a copy of the database to validate before running on the real prod environment.
Added Later
To prevent EF Migrations from doing anything automatic at all, a custom initializer strategy can be used. See my blog or the Deploying EF Code First Apps to Production Database Stack Overflow question.

Related

Entity Framework bug? "Context changed" Error, even when not

I have gotten myself into an odd Groundhog Day scenario with an MVC application of mine.
Unless I apply my workaround (Later in this question) each time I debug the application I'm presented with this error:
The model backing the 'UsersContext' context has changed since the
database was created. Consider using Code First Migrations to update
the database (http://go.microsoft.com/fwlink/?LinkId=238269).
I have not changed the model.
My workaround workflow is:
Add-Migration WHATEVERNAME (Makes a blank migration)
Delete this migration.
Run: Update-Database
Recompile & Run (Now without error)
Notes:
The __MigrationHistory hashes of the latest migration match in both script and in the database.
I have my MVC application & EF project as separate projects.
I have tried creating an -IgnoreChanges migration, to see if applying this would mitigate the issue. It did not.
This is quite frustrating, how would I solve this issue permanently?
Note: Automatic migrations are not suitable for my scenario.
Well, it's almost impossible to understand what's wrong without knowing much more detail. So all I can do is give you some clues of what you could try.
Stopping and restarting the app should not cause the DB to get out of date. Is it only when debugging? Have you tried running the app without debugging? Then recycle the app pool and running the app again.
Do you have any weird post-build step that will overwrite some DLL in your "bin" folder?
Is your app doing something that changes the database schema, thereby invalidating it when you next start up? Run SQL profiler to check what is happening to the DB when your app starts up.
Migrate back to the first version of your schema, and then back again (backup your DB first):
update-database -TargetMigration:0 -verbose
then
update-database -verbose
Temporarily comment out the bulk of your app to try to isolate the cause.
Create a brand new app with EF configured in the same way, copy the connection string and see if it happens for that. If not, then there must be something different. If yes, then show us your EF settings.
Hopefully something here that could give you an idea at least. Good luck!
Enabling migrations sets up the whole migration system. But to enable automatic migrations you have to include -EnableAutomaticMigrations which simply adds the line
AutomaticMigrationsEnabled = true;
into the newly generated Configurations.cs file.
In conjunction with the database initializer, development turnaround is more streamlined because you no longer have to type add-migration and update-database every time you make a change. That will happen automatically now. However, that’s not enough, if you want column removals you have to also perform step 3, where automatic data loss is supported.
When you are ready to release software (internally or externally) where you need strict version control and to upgrade databases on site, you should remove automatic migrations and add a manual migration point.
This can happen when updating to EF6 which made schema changes to the _MigrationHistory table (https://msdn.microsoft.com/en-us/data/jj591621)
The EF6 version has a new column ContextKey so the migration is probably trying to add that column.
I'm guessing if you scaffold it will just be making those changes - or perhaps there's something you changed a long time ago that wasn't 'picked up' yet for some reason.
OR if you just don't want to deal with it right now you can disable migrations temporarily.
System.Data.Entity.Database.SetInitializer<UsersContext>(null);

Disable code first migrations per user

We're a team of 4 developers and have been developing a product using Code First Migrations for about 21 months. We've had countless issues and headaches using this code first migrations (as we all make db changes and checkins simultaneously) and are currently considering our alternatives. We are currently setting up TeamCity as our build server so that when we check in the solution is automatically built and if everything is good the code is automatically pushed out to a preview server.
We were going to try a situation where we don't check in migrations, just the model changes, and we all build the migrations locally, so we avoid the headache of merging/getting the order out of sync. Then when we're finished our development on a certain package of work we'll create one migration that we can effectively run on live environments. What we were wondering is if there's anyway to turn off/disable code first migrations on some sort of config so that we can develop using code first migrations but have TeamCity successfully build the project and then manually update the database without using migrations?
I've read that you can disable migrations by deleting the migrations folder that was originally created when migrations were enabled and delete the MigrationHistory table but we would still want this locally, however, we would want TeamCity to ignore the migrations aspect whilst we're still developing. Only when we completed the package of work would we want to enable the migrations again so the db can be updated and the code rolled out to our preview server.
I hope this makes sense and if anybody has any experience of life after code first migrations please tell all!
Thanks,
Automatic execution of migrations is configured in the migrations Configuration class (automatically generated when you first enable migrations):
internal sealed class Configuration : DbMigrationsConfiguration<MigrationsContext>
{
public Configuration()
{
AutomaticMigrationsEnabled = false;
}
//...
}

Is there a good migration management/clean-up strategy after completing a Rails project?

As I go through the development of an application, in my development environment, I make mistakes and create tables that need to be modified later - as I use the app and see the folly of earlier design decisions.
But when I push to production, I don't want to replicate all those changes when I can just create the 'perfect' table in one migration.
Is there a strategy or something I can use that can help me do that?
If this is the initial push to production, you should be able to copy your schema.rb contents (which should reflect the schema after all migrations were applied) into one giant migration file, and remove all previous migration files.
If your production environment has already been created and the database has been migrated up to a point, then you'll need to use something more intelligent that can bridge the gap between the current state and the latest schema. Unfortunately, I'm not aware of any such project at this time.

Rails - authoritative source for your database schema?

I have Rails app, and every once in a while, when I bring new developer onboard they exclaim that they should be able to produce the current DB schema in their dev environment by running the whole history of the migrations. I personally don't think that migrations is the authoritative source for your schema. Right now what we do is load a production copy of the DB, with the current schema, onto the dev machine. And, from there, the schema can be maintained via incremental migrations.
So my question are:
What is the authoritative source of your schema on a Rails project?
What is now considered the best-practice way to maintain your DB schema?
I do not consider migrations to be the authoritative source for your schema. Migrations are extremely powerful but optional. Some developers use alternative workflows especially in environments where DBA's insist on strong referential integrity and DBMS-enforced constraints. I suggest looking at the official RoR Guide on Migrations for more information. The db/schema.db (or db/{env}_structure.sql) file is the authoritative source for your schema. Many developers will purge old migrations as projects get older so running each migration will not necessarily produce a working database. It also takes a long time to run through a hundreds of migrations. Rails uses schema.db (or the sql dump file) to build the test database and of course when running rake db:setup which is the recommended way of creating a new database for your application.
Bottom like is that rake db:setup should always produce a working database regardless of migrations. Developers can use this to create new environments and Rails uses this to run your tests.
http://guides.rubyonrails.org/migrations.html#schema-dumps-and-source-control
Normally, running the succession of all migrations should produce your actual DB schema (if it's not the case, then you didn't use your migrations correctly*).
Another way of doing is to copy over the schema.rb (created/updated when you migrate), which is used by rake db:setup and should produce an exact copy of the schema you have in production (unless, again, you didn't use migrations correctly*).
Then, if you need "sample data", you can insert it using the db/seeds.rb file, which contains ruby code that can access your models, and thus create and persist new entities & so on...
*: There are cases where you can't put all your database changes in migrations in a "usual" way (it is uncommon and should be avoided if possible)... These should be included in migrations however (in plain SQL execution statements), or the changes would need to be made manually on the dev DB as well... And then using a snapshot of prod. is sometimes more convenient. But again, I would discourage doing so.

Rolling up Migrations?

As I understand it the point of migrations is so you can revert the database back to a known state during the last stages of development.
Right now I'm still "fleshing" out my first Rails app and I'm wondering if its ok to roll up my migrations into bigger ones rather than dozens of changes.
The point of migrations is that you basically have a log of database changes, so then other developers can know what changes have been made, or to make sure your production environment gets the same changes you made during development.
As for your question: sure. If you create a new model, and then after a few minutes decide "this column could just be a string instead of text", roll back your migration, and change the column and then migrate again. No need to create a new migration.
Unless you've already committed the previous migration to source control that may have been fetched by other developers, or you've already applied the migration on the production server. Then you should use a new migration.
As an addendum to rspeicher, I limit the constraint to whether a migration has been released, not to whether it has been made available to other developers. If it's still pre-release, then the development team can be informed of any need to run migrations for any updates of the master code repository by using post-fetch hooks for the SCM being used. This is true of any configuration management change, not just migrations. For example, changing an implementation of something in the initializers folder may have no effect on a running instance of script/server in development mode. This is a ultimately a necessary mechanism for most teams in most technologies as well as for some configurations of continuous integration. Or, you need excellent communications channels in the team to make sure that everyone knows that a configuration change and restart is necessary.

Resources