Tuesday, March 13, 2012

The model backing the 'MyDBContext' context has changed since the database was created. Either manually delete/update the database, or call Database.SetInitializer with an IDatabaseInitializer instance. For example, the DropCreateDatabaseIfModelChanges strategy will automatically delete and recreate the database, and optionally seed it with new data.

Today I have faced a problem when working with a previous developed ASP.NET MVC application. Just copy the database(.sdf) from previous version to new version. I have changed some validation and business logic. But when run the application it shows me the following error:


The model backing the 'MyDBContext' context has changed since the database was created. Either manually delete/update the database, or call Database.SetInitializer with an IDatabaseInitializer instance. For example, the DropCreateDatabaseIfModelChanges strategy will automatically delete and recreate the database, and optionally seed it with new data.


It was a running application after searching on community I have got the solution.

Solution 1:
However, even if you manually update the database to follow the model, this exception will still occur. The reason is that EF does not check model schema completely: tables, columns, keys, indexes etc.

It calculates a hash of the model and compares with the hash of model which the database was built with. The hash is stored at EdmMetadata table.



Tell EF do not use this hash check. For this change your DbContext class like this:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
  base.OnModelCreating(modelBuilder);
  modelBuilder.Conventions.Remove > IncludeMetadataConvention < ();
}

Solution 2:

Recalculate the hash of the new model and update it manually in the database:

System.Data.Entity.Infrastructure.EdmMetadata.TryGetModelHash(context)

will return new hash, you then can update EdmMetadata table with Sql. I think that  this way is more correct, because gives you schema validation feature and still allows to make upgrade scripts:
1. Upgrade DB with SQL
2. Reset ModelHash value
3. Run
For more details:
http://blog.oneunicorn.com/2011/04/08/code-first-what-is-that-edmmetadata-table/
http://stackoverflow.com/questions/4031431/entity-framework-ctp-4-code-first-custom-database-initializer


Solution 3:
We need to update the table in Sql Server to have the additional column you added to your entitiy class.

Database.SetInitializer<MovieDBContext>(new DropCreateDatabaseIfModelChanges<MovieDBContext>());

This line is used for in order to allow to edit database by making changes to Model objects.Add this line in Global.asax at Application_Start() method.

Inside the Application_Start method, define the Database initializer with one among the two options.

DropCreateDatabaseAlways: This will drop and recreate the database in every application start.

DropCreateDatabaseIfModelChanges: This will drop and create the database only if the underlined model changes.

Sample code:

protected void Application_Start()
{
Database.SetInitializer<MovieDBContext>(new DropCreateDatabaseIfModelChanges<MovieDBContext>());

AreaRegistration.RegisterAllAreas();

RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
}

Now it is working perfectly.


Note: DropCreateDatabaseIfModelChanges should only be use early on in development, never on a production machine. If you pushed to a production machine and made schema changes, you'd loose all your data.

No comments:

Method 'StartWorkflowOnListItem' in type 'Microsoft.SharePoint.WorkflowServices.FabricWorkflowInstanceProvider'

Exception: Method 'StartWorkflowOnListItem' in type 'Microsoft.SharePoint.WorkflowServices.FabricWorkflowInstanceProvider'...