Code First Entity Framework 6 rebuild project triggers context change - c#

I have set up a solution which contains a number of projects, including one for my models and one for the database contexts (and associated migrations). I have two contexts - one for my standard database (ContextA) and one for the ASP.NET Identity tables (ContextB). (I couldn't work out how to get these to "merge" into my existing context, but they do both point to the same DB).
Every single time I rebuild any project in my solution, I get the error "model backing the 'ContextA' context has changed since the database was created", and I have to do an update-database for EITHER context in order to continue.
I have found that I don't need to do an add-migration at all (and doing so for either context results in empty Up() and Down() methods).
Can anyone tell me what would be triggering the context to thing the model has changed?
Should I consider just adding Update-Database to the build script?

The migrationhistory table in your database is usually associated with one context which then compares against your models to keep everything in sync. I can see why you get this odd behavior. I have two contexts per application instance but I also have two databases.
I recommend you merge your context and models or split them into different databases (which ever makes sense in your app design). This will resolve your issue.

Related

Entity Framework Core: create a migration that merges multiple DbContexts (with multiple migrations)

When I started a project (an Identity Server 4 server) I created an ApplicationDBContext (which inherits from ASP.NET IdentityContext and hassome custom tables) and used the ConfigurationDBContext as well as the PersistedGrantDBContext from Identity Server 4. I created 3 migrations (one for each DBContext). Though the data is in the same database (so a single database).
Now I refactored my code giving me a new DBContext having all 3 databases in one DBContext.
My problem is the new migration.
So far I deleted the old DBContexts and created a migration that creates the exact same database again when I run it against an empty database.
But when it comes to migrate an existing database (with existing data) it raises the exception that table X already exists.
I assume this is because I have deleted the old code and the old migrations.
So, how can I create a migration that merges 3 different DBContexts into a single new DBContext.
I assume if I leave the old code in place and use the old migrations too it tries to create the tables multiple times (since they are in the old splitted migrations and the new combined migration)?
Is there a way to tell the new migration to not throw an error if the table exists (and take the table as it is since it is the same layout).
In my opinion, you have to keep 3 default(old) contexts.
Because:
It's a very bad practice to merge 3 in 1 and retire their default contexts.
all those 3 contexts have their APIs to play with their data, which APIs will make sure all data is well maintained and which APIs will make Code-First is real code-first, but not a Code-Once.
if you merge them to one, how would you keep Database&APIs up-to-date with those projects? and how would you implement those APIs, you want to write them again?
Code-First is designed mainly for database changes, if you do need to custom them, just customize them in their own context. then you can use your own context to combine them to one, but unfortunately, you have to carefully maintain your migration code to make sure no conflicts with each other.
I suggest you use IdentityContext as base for your new context and don't merge the other 2 to here. which you can keep 3 contexts.

Do I need a migration for EF code first when the database does not exist in SQL Azure?

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...

Entity framework: two distinct contexts and one database

Is it possible, in a code-first approach, to define two different context classes and use them simultaneously?
The database schema is already given and I cannot modify it (besides the creation of some new tables).
The problem I'm facing is that I'm getting "The model backing... has changed" error. It seems there's some kind of collision between the two contexts.
Note that each context includes a different set of tables, so sync problems aren't a concern.
Assuming you are using EF 6 or higher, this can be done either by the ContextKey-Property of DbMigrationsConfiguration (this will make the MigrationsHistory table multi tenant by ContextKey) or by setting HasDefaultSchema in OnModelCreating (this will enable multiple MigrationsHistory tables, one for each schema). For further instructions see the Documentation.

Multiple Database Files/Context ASP.NET MVC

My understanding is that a context connects to a database via a connection string specified in web.config. When I create new scaffolds it creates new database .mdf files with a new connection string. I am coming from rails active record with one database and one connection string. So why does asp.net do it differently? Why have multiple database files?
Also I changed the connection string for the user model to my default site database called Toolsite to simplify things and put the users in the same db as everything else -
public ApplicationDbContext()
: base("Toolsite")
{
System.Diagnostics.Debug.Write(Database.Connection.ConnectionString);
}
and this caused a Invalid object name 'dbo.AspNetUsers'. exception even though the table AspNetUsers exists in the database "ToolSite". Is there any other part in the server code that needs to change?
The default MVC project scaffold has always been a pet peeve of mine. When you create a new MVC project with auth, you get a user model and an application context to wire it up. That's great, in one respect, because it lets you immediately run the project with no extra configuration. However, they stupidly decided to put the user model and the application context in the same .cs file, so it confuses developers not familiar with the setup into thinking that the two are intrinsically linked.
In reality, MVC applications are designed to have a single context, and you should actually add your models to the existing context created by the scaffold, rather than create a new, separate context. The only reason to have multiple contexts is if you're literally dealing with multiple databases, and then, only really because you're dealing with existing databases in addition to your application-specific database. In other words, you should only have a single context that is tied to migrations and then you may or may not have additional contexts that operate on a database-first basis. Once you understand that, it becomes far less confusing to work with a scaffolded project.

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