I have a webapp uses EF, and a separated EF migration project.
The webapp is deployed and running.
Now I manually run EF migration which alter the db schemas, which make it very different from before.
So what will happen to the running webapp? Does it crash? What is best way to handle this situation?
If you are using Code First (that apparently you are), it will crash with the following error:
The model backing the 'dbContext' context has changed since the
database was created.
Otherwise, depending on the changes you have made (that seem to be a lot) it still has a good chance of crashing.
A safe approach is to first stop the app and then update the database and the app.
Related
I have tried lots of variations of EF migration v6.0.1 (from no database, to empty databases to existing databases) and I have a particular problem with Azure DB instances not being able to correctly be created on first deploy using Octopus deploy.
There are a number of places where this could be going wrong, so I thought I would check some basics of EF Code First migration with you fine people if I may:
If I create a code-first model, and know that the database does not exist in the intended target database server on Azure. With the default of 'CreateDatabaseIfNotExists' approach and with AutomaticMigrations disabled;
If I then call 'migrate.exe' with the assembly containing my DbContext and migration Configuration will I get a new database created with the current state of the model? or will I get a new database with nothing in it? i.e. do I need to explicitly 'add-migration' for the initial state of the model?
I have read in the documentation that the database instance should be created automatically by the migration process, but no one states clearly (at least to me) that this newly created database will be generated with the current model without a formal 'initial state' migration created.
So the question is this: do I need an explicit migration model generated for migrate.exe to work from?
Through whatever means I try, I get a database but the application launches with the unfriendly message "Model compatibility cannot be checked because the database does not contain model metadata. Model compatibility can only be checked for databases created using Code First or Code First Migrations." Remembering that this is the same application library that just created the database in the first place (from scratch) I fail to understand how this has happened!
I did manually delete the target database a few times via SQL Server management studio, is this bad? Have I removed some vital user account that I need to recover?
Migrations and the Database Initializer CreateDatabaseIfNotExists are not the same.
Migrations uses the Database Initializer MigrateDatabaseToLatestVersion, which relies upon a special table in the database _MigrationsHistory.
By contrast, CreateDatabaseIfNotExists is one of the Database Initializers which relies upon the special database table EdmMetadata. It does exactly as it implies: Creates a database with tables matching the current state of the model, i.e. a table for each DbSet<T>, only when the database does not exist.
The specific error you have quoted here, Model compatibility cannot be checked because the database does not contain model metadata., occurs due to the existence of DbSet<T> objects which were added to the code base after the initial database creation, and do not exist in EdmMetadata.
There are 4 basic Database Initializers available, 3 of which are for use when migrations is not being used:
CreateDatabaseIfNotExists
DropCreateDatabaseWhenModelChanges
DropCreateDatabaseAlways
Also note, the 4th Initializer, MigrateDatabaseToLatestVersion, will allow you to use Migrations even if AutomaticMigrations is disabled; AutomaticMigrations serves a diffierent purpose, and does not interact with the Database Initializers directly.
If you intend to use Migrations, you should change the Database Initializer to MigrateDatabaseToLatestVersion and forget about the other 3. If, instead, you intend to not use Migrations, then the choice of Initializer is situational.
CreateDatabaseIfNotExists will be more appropriate when you are certain that your data model is not undergoing active change, and you only intend to be concerned with database creation on a new deployment. This Initializer will elp ensure that you do not have any issues with accidental deletion of a database or live data.
DropCreateDatabaseWhenModelChanges is most appropriate in development, when you are changing the model fairly often, and want to be able to verify these changes to the model. It would not be appropriate for a production server, as changes to the model could inadvertently cause the database to be recreated.
DropCreateDatabaseAlways is only appropriate in testing, where your database is created from scratch every time you run your tests.
Migrations differs from these 3 Database Initializers, in that it never drops the database, it instead uses Data Motion to execute a series of Create Table and Drop Table SQL calls.
You also can use Update-Database -Script -SourceMigration:0 in the Package Manager Console at any time, no matter which Database Initializer you are using, to generate a full SQL script that can be run against a server to recreate the database.
Firstly, many thanks to Claies who helped me get to the bottom of this problem. I have accepted his answer as correct as ultimately it was a combination of his response and a few additional bits of reading that got me to my solution.
In answer to the actual posts question 'Do I need a migration for EF code first when the database does not exist in SQL Azure?' the answer is yes you do if you have disabled automatic migrations. But there is a little more to be aware of:
The Azure aspects of this particular problem are actually irrelevant in my situation. My problem was two-fold:
The migration being generated was out of sync with respect to the target model. What do I mean? I mean, that I was generating the migration script from my local database which itself was not in sync with the local codebase which created a migration that was incorrect. This can be seen by comparing the first few lines of the Model text in the __MigrationHistory. This awareness was helped by referring to this helpful post which explains how it works.
And more embarrassingly (I'm sure we've all done it) is that my octopus deployment of the web site itself (using Octopack) somehow neglected to include the Web.Config file. From what I can tell, this may have occurred after I installed a transform extension to Visual Studio. Within my nuget package I can see that there is a web.config.transform file but not a web.config. Basically this meant that when the application started up, it had no configuration file to turn to, no connections string at all. But this resulted in the slightly misleading error
Model compatibility cannot be checked because the database does not
contain model metadata.
Whereas what it should have said was, there isn't a connection string you idiot.
Hopefully this helps people understand the process a little better after reading Claies answer and also that blog-post. First though, check you have a web.config file and that it has a connection string in it...
I have been playing around with EF6 CodeFirst and Migrations. So far all good. But there is one thing I don't understand (conceptually):
In my specific case I am determining the database to connect to at runtime (via some external config XML / JSON or similar). So during development I am a) not certain what database it is I am working with and b) do not necessarily have one available. But EF still requires one, because otherwise I cannot use Update-Database. And if I cannot use Update-Database, I cannot scaffold further migrations.
Is there something I am missing or do I necessarily need a dev-database to develop something using EF6?
The real problem I face is that Update-Database fails with an error telling me that connecting to a DB failed.
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?
What am I doing wrong. I have got a user DbContext setup and working when I originally created the Code-First with powershell it all worked fine.
I implemented Database Initializer as expected on application start.
Database.SetInitializer<UserDbContext>(new CreateDatabaseIfNotExists<UserDbContext>());
Just to test out if it really creates the database I actually dropped the database and now I am stuck the database will not be created. I am using SQL Server 2012, any idea what could be wrong.
The error message I am getting is
System.InvalidOperationException: Migrations is enabled for context 'UserDbContext' but the database does not exist or contains no mapped tables. Use Migrations to create the database and its tables, for example by running the 'Update-Database' command from the Package Manager Console.
I have tried the same from Package Manager console and it is still give me the same message.
Finally figured the solutions, not sure why or what. Changed my Database initializer to MigrateDatabaseToLatestVersion instead of CreateDatabaseIfNotExists worked.
Database.SetInitializer<UserDbContext>(new MigrateDatabaseToLatestVersion<UserDbContext, Configuration>());
Edit:
With your new error message the problem comes from you having migrations enabled and already ran a migration (probably the first creation of the database) and since you dropped the DB the migration history has been lost. If your not using Automatic migrations you can not go in and make changes to the database your self and expect code-first to know about it. Try disabling migrations and re-enabling them to see if that clears out the migration history.
You will need to make a call into the DB either as a read or insert of data for the DB to initially be created. The code you use only tells EF how to deal with a database if one does not exist when it tries to find it. For me I use the method outlined at http://www.codeproject.com/Tips/411288/Ensure-Your-Code-First-DB-is-Always-Initialized
I'm using the same model for multiple applications: MVC3 web app, Windows services, and a console application. When I start the MVC3 web app, it generates the database. I can restart it, and everything is fine. But when I start the console application I get an error:
The model backing the '...Context' context has changed since the
database was created. Consider using Code First Migrations to update
the database (http://go.microsoft.com/fwlink/?LinkId=238269).
Same occurs when I drop the database, start console app, I can restart this, and everything is fine too. When I start the MVC web app. Crash: model backing... etc.
In EF4.1 removing the EdmMeta table 'solved' the problem. But since EF4.3 doesn't have such a table anymore I can't fix it that way. I've checked that all apps refer to same model dll's. I've double checked that all projects reference to EF4.3 so that's not the cause of the problem.
Any constructive help would be appreciated.
Regards,
Erwin van Dijk.
You should not let multiple applications to create the database - that can result in unexpected deletion of your database. Simply choose one which will be responsible for database creation and in all other use:
Database.SetInitializer<YourContext>(null);
Also add this to your OnModelCreating in your derived DbContext:
modelBuilder.Conventions.Remove<IncludeMetadataConvention>();
This should avoid problems with hash computation.
More about reasons why problems with hash computation exist is described here.