可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
The error message :
\"The model backing the \'AddressBook\' 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 RecreateDatabaseIfModelChanges strategy will automatically delete and recreate the database, and optionally seed it with new data.\"
I am trying to use the code-first feature and following is what I wrote:
var modelBuilder = new ModelBuilder();
var model = modelBuilder.CreateModel();
using (AddressBook context = new AddressBook(model))
{
var contact = new Contact
{
ContactID = 10000,
FirstName = \"Brian\",
LastName = \"Lara\",
ModifiedDate = DateTime.Now,
AddDate = DateTime.Now,
Title = \"Mr.\"
};
context.contacts.Add(contact);
int result = context.SaveChanges();
Console.WriteLine(\"Result :- \"+ result.ToString());
}
The context class:
public class AddressBook : DbContext
{
public AddressBook()
{ }
public AddressBook(DbModel AddressBook)
: base(AddressBook)
{
}
public DbSet<Contact> contacts { get; set; }
public DbSet<Address> Addresses { get; set; }
}
and the connection string:
<?xml version=\"1.0\" encoding=\"utf-8\" ?>
<configuration>
<connectionStrings>
<add name=\"AddressBook\" providerName=\"System.Data.SqlClient\"
connectionString=\"Data Source=MyMachine;Initial Catalog=AddressBook;
Integrated Security=True;MultipleActiveResultSets=True;\"/>
</connectionStrings>
</configuration>
So, the database name is \"AddressBook\" and the error happens when I trying to add the contact object to the context. Am I missing anything here?
回答1:
Now it\'s:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
Database.SetInitializer<YourDbContext>(null);
base.OnModelCreating(modelBuilder);
}
in your YourDbContext.cs file.
回答2:
Here\'s some information from Scott Gu\'s Blog posted by Jeff on what\'s actually taking place:
For those who are seeing this exception:
\"The model backing the \'Production\' context has changed since the
database was created. Either manually delete/update the database, or
call Database.SetInitializer
with an IDatabaseInitializer
instance.\"
Here is what is going on and what to do about it:
When a model is first created, we run a DatabaseInitializer to do
things like create the database if it\'s not there or add seed data.
The default DatabaseInitializer tries to compare the database schema
needed to use the model with a hash of the schema stored in an
EdmMetadata table that is created with a database (when Code First is
the one creating the database). Existing databases won’t have the
EdmMetadata table and so won’t have the hash…and the implementation
today will throw if that table is missing. We\'ll work on changing this
behavior before we ship the fial version since it is the default.
Until then, existing databases do not generally need any database
initializer so it can be turned off for your context type by calling:
Database.SetInitializer<YourDbContext>(null);
Jeff
回答3:
For Entity Framework 5.0.0.0 - 6.1.3
You DO indeed want to do the following:
1. using System.Data.Entity; to startup file (console app --> Program.cs / mvc --> global.asax
2. Database.SetInitializer<YourDatabaseContext>(null);
Yes, Matt Frear is correct. UPDATE -EDIT: Caveat is that I agree with others in that instead of adding this code to global.asax added to your DbContext class
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// other code
Database.SetInitializer<YOURContext>(null);
// more code
}
As others mentioned this also is good for handling the unit testing.
Currently I am using this with Entity Framework 6.1.3 /.net 4.6.1
回答4:
This fix no longer works after CTP5.
You have to do Database.SetInitializer<YourContext>(null);
回答5:
Just found out the answer and thought of updating here. Just need to do the following.
public class AddressBook: DbContext
{
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.IncludeMetadataInDatabase = false;
}
}
回答6:
Just run the followng sql command in SQL Server Management Studio:
delete FROM [dbo].[__MigrationHistory]
回答7:
Or you can put this line in your Global.asax.cs file under Application_Start():
System.Data.Entity.Database.SetInitializer(new System.Data.Entity.DropCreateDatabaseIfModelChanges<ProjectName.Path.Context>());
Make sure to change ProjectName.Path.Context to your namespace and context. If using code first this will delete and create a new database whenever any changes are made to the schema.
回答8:
I spent many days to solve this issue, analyzed many different posts and tried many options and finally fixed.
This 2 projects in my solution using EF code first migrations:
- Console Application \"DataModel\" that mainly using as assembly which contains all my code first entities, DbContext, Mirgations and generic repository. I have included to this project separate empty local database file (in DataModel/App_Data folder) to be able generate migrations from Package Manager Console.
- WebApi, which references to DataModel project and uses local database file from WebApi/App_Data folder, that not included in project
I got this error when requested WebApi...
My environment:
- Windows 8.1 x64
- Visual Studio 2015 Professional with Update 1
- all my projects targeted for .NET Framework 4.6.1
- EntityFramework 6.1.3 from NuGet
Here I collected all the remarks you should pay attention and all conditions/requirements which must be met, to avoid mentioned exception :
- You should use only one version of EntityFramework Nuget package for all projects in your solution.
- Database, created by running sequentially all migration scripts should have the same structure/schema as you target database and correspond to entity model. Following 3 things must exactly correspond/reflect/match each other:
- Your all migration script up to last
- Current code first entity model state (DbContext, entities)
- Target database
- Target database (mdf file) should be updated/correspond up to last migration script. Verify that \"__MigrationHistory\" table in your target database contains records for all migration scripts that you have, it means that all migration scripts was successfully applied to that database. I recommend you to use Visual Studio for generation correct code first entities and context that corresponds to your database, Project -> Add New Item -> ADO.NET Entity Data Model -> Code First from database:
Of course, as an alternative, if you have no database you can write manually model (code first entities and context) and then generate initial migration and database.
Name of connection string e.g. MyConnectionString in config file of startup project (Web.config/App.config):
<configuration>
<connectionStrings>
<add name=\"MyConnectionString\" connectionString=\"...\">
</connectionStrings>
<configuration>
should be equal to parameter passed in constructor of your DbContext:
public partial class MyDbContext : DbContext
{
public MyDbContext()
: base(\"name=MyConnectionString\"){}
...
- Before using Package Manager Console, make sure that you are using correct database for update or generate migration and needed project is set as startup project of solution. For connect to database it will use connection string from that .config file, which in project, that is set as startup project.
And the main, which fixed my issue: It is weird, but in my WebApi/bin folder DataModel.exe was old, not refreshed since last build. Since migrations was embedded in my assembly DataModel.exe then my WebApi updated database using old mirgations. I was confused why after updating database in WebApi it not corresponds to latest migration script from DataModel. Following code automatically creates(if not exists) or updates to latest migration local database in my WebApi/App_Data folder.
public class WebApiApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
Database.SetInitializer(new MigrateDatabaseToLatestVersion<ODS_DbContext, Configuration>());
...
I tried clean and rebuild solution but it did not help, than I completely removed
bin and obj folders from WebApi, deleted database files from WebApi/App_Data, built, restarted WebApi, made request to it, it created correct database - lazy initialization (using lines above), which corresponds to latest migration and exception didn\'t appear more.
So, this may fix your problem:
- remove manually bin, obj folders from your startup project (which generates/updates your database)
- build your startup project or better clean and rebuild all you solution.
- recreate database by starting project (will execute lines above) or use Package Manager Console \"update-database\" command.
- manually check whether generated db and __MirgationHistory corresponds to latest migration script.
回答9:
For me, with the upgrade to 4.3.1, I just truncate the EdmMetaData table or just delete it outright.
回答10:
For VB.NET developers:
Add the following line to the Glabal.asax.vb file, at the end of method Application_Start()
Database.SetInitializer(Of ApplicationDbContext)(Nothing)
Change ApplicationDbContext to your specific Db context.
回答11:
I had this issue and it turned out that one project was pointing to SQLExpress but the one with the problem was pointing to LocalDb. (in their respective web.config). Silly oversight but worth noting here in case anyone else is troubleshooting this issue.
回答12:
I had the same issue - re-adding the migration and updating the database didn\'t work and none of the answers above seemed right. Then inspiration hit me - I\'m using multiple tiers (one web, one data, and one business). The data layer has the context and all the models. The web layer never threw this exception - it was the business layer (which I set as console application for testing and debugging). Turns out the business layer wasn\'t using the right connection string to get the db and make the context. So I added the connection string to the app config of the business layer (and the data layer) and viola it works. Putting this here for others who may encounter the same issue.
回答13:
I use the Database.CompatibleWithModel method (available in EF5) to test if the model and DB match before I use it. I call this method just after creating the context...
// test the context to see if the model is out of sync with the db...
if (!MyContext.Database.CompatibleWithModel(true))
{
// delete the old version of the database...
if (File.Exists(databaseFileName))
File.Delete(databaseFileName);
MyContext.Database.Initialize(true);
// re-populate database
}
回答14:
It means that there were some changes on the context which have not been executed.
Please run Add-Migration first to generate the changes that we have done (the changes that we might not aware)
And then run Update-Database
回答15:
I had the same problem when we used one database for two applications. Setting disableDatabaseInitialization=\"true\"
in context type section works for me.
<entityFramework>
<providers>
<provider invariantName=\"System.Data.SqlClient\" type=\"System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer\" />
</providers>
<contexts>
<context type=\"PreferencesContext, Preferences\" disableDatabaseInitialization=\"true\">
<databaseInitializer type=\"System.Data.Entity.MigrateDatabaseToLatestVersion`2[[PreferencesContext, Preferences], [Migrations.Configuration, Preferences]], EntityFramework\" />
</context>
</contexts>
See more details https://msdn.microsoft.com/en-us/data/jj556606.aspx
回答16:
Just in case someone has the same scenario as mine.
I have database first EF and at the same time using the asp.net identity
so I have two connectionStrings in my webconfig, and there is no problem with that. It happened that I created/run the scripts to generate manually the asp.net identity tables which I should not.
so DROP first all the asp.net identity tables created by you manually/from scripts.
DROP TABLE __MigrationHistory
DROP TABLE AspNetRoles
DROP TABLE AspNetUserClaims
DROP TABLE AspNetUserLogins
DROP TABLE AspNetUserRoles
DROP TABLE AspNetUsers
回答17:
After some research on this topic, I found that the error is occured basically if you have an instance of db created previously on your local sql server express. So whenever you have updates on db and try to update the db/run some code on db without running Update Database
command using Package Manager Console
; first of all, you have to delete previous db on our local sql express manually.
Also, this solution works unless you have AutomaticMigrationsEnabled = false;
in your Configuration.
If you work with a version control system (git,svn,etc.) and some other developers update db objects in production phase then this error rises whenever you update your code base and run the application.
As stated above, there are some solutions for this on code base. However, this is the most practical one for some cases.
回答18:
I am reading the Pro ASP.NET MVC 4 book as well, and ran into the same problem you were having. For me, I started having the problem after making the changes prescribed in the \'Adding Model Validation\' section of the book. The way I resolved the problem is by moving my database from the localdb to the full-blown SQL Server 2012 server. (BTW, I know that I am lucky I could switch to the full-blown version, so don\'t hate me. ;-))) There must be something with the communication to the db that is causing the problem.
回答19:
Check this following steps
- Database.SetInitializer(null); -->in Global.asax.cs
2.
- your Context class name should match with
check it
回答20:
Modify Global.asax.cs
, including the Application_Start
event with:
Database.SetInitializer<YourDatabaseContext>(
new DropCreateDatabaseIfModelChanges<YourDatabaseContext>());
回答21:
This error can indicate an issue with your connection string and whether your connection string name matches the Database context declaration.
I had this error because I had named the local database wrongly (silly mistake) and the name of the connection string in web.config of \"DefaultConnection\" did not match the MyDbContext i.e.
public MyDbContext(): base(\"DefaultConnection\")
{}
<connectionStrings>
<add name=\"DefaultConnection\" ...
</connectionStrings>
回答22:
Try using Database SetInitializer which belongs to using System.Data.Entity;
In Global.asax
protected void Application_Start()
{
Database.SetInitializer(new DropCreateDatabaseIfModelChanges<yourContext>());
}
This will create new database everytime your model is changed.But your database would be empty.In order to fill it with dummy data you can use Seeding. Which you can implement as :
Seeding ::
protected void Application_Start()
{
Database.SetInitializer(new AddressBookInitializer());
----rest code---
}
public class AddressBookInitializer : DropCreateDatabaseIfModelChanges<AddressBook>
{
protected override void Seed(AddressBook context)
{
context.yourmodel.Add(
{
});
base.Seed(context);
}
}
回答23:
It\'s weird, but all answers here were useless for me.
For me worked initializer
MigrateDatabaseToLatestVersion
Here\'s my solution (I know, it can be much simplier, but it\'s how I use it):
class MyDbMigrateToLatest : MigrateDatabaseToLatestVersion<MyDbContext, Configuration>
{
}
public class MyDbContext: DbContext
{
public MyDbContext() : base(\"DbName\")
{
SetInitializer();
}
public MyDbContext(string connString) : base(connString)
{
SetInitializer();
}
private static void SetInitializer()
{
if (ConfigurationManager.AppSettings[\"RebuildDatabaseOnStart\"] == \"true\")
Database.SetInitializer(new MyDbInitializerForTesting());
else
Database.SetInitializer(new MyDbMigrateToLatest());
}
}
public sealed class Configuration : DbMigrationsConfiguration<MyDbContext>
{
public Configuration()
{
AutomaticMigrationsEnabled = true;
}
protected override void Seed(MyDbContext context)
{
// Whatever
}
}
MyDbInitializerForTesting just inherits from DropCreateDatabaseAlways so in some specific case (testing), whole database is rebuilded. Otherwise it\'s migrated to latest version.
My source: https://msdn.microsoft.com/en-us/data/jj591621.aspx#specific
回答24:
Good suggestion, however, nt so accurate in all cases. I figure one out.
Please you need to make sure you run \"enable-migrations\" using PM windows in Visual Studio, and Migration folder would be added to you project.
Make sure the two c# class files added to the folder on will contain all your models and their respective properties.
If you have all that build the solution, and publis for deployment.
The logic is that the existing metadata cannot be overwritten because your application has no metadata to replace the current. As a result you are getting this error \"The model backing the context has changed since the database was created\"
回答25:
None of these solutions would work for us (other than disabling the schema checking altogether). In the end we had a miss-match in our version of Newtonsoft.json
Our AppConfig did not get updated correctly:
<dependentAssembly>
<assemblyIdentity name=\"Newtonsoft.Json\" publicKeyToken=\"30ad4fe6b2a6aeed\" culture=\"neutral\" />
<bindingRedirect oldVersion=\"0.0.0.0-7.0.0.0\" newVersion=\"7.0.0.0\" />
</dependentAssembly>
The solution was to correct the assembly version to the one we were actually deploying
<dependentAssembly>
<assemblyIdentity name=\"Newtonsoft.Json\" publicKeyToken=\"30ad4fe6b2a6aeed\" culture=\"neutral\" />
<bindingRedirect oldVersion=\"0.0.0.0-7.0.0.0\" newVersion=\"10.0.0.0\" />
</dependentAssembly>
回答26:
Create custom context initializer:
public class MyDbContextInitializer : MigrateDatabaseToLatestVersion<MyDbContext, Migrations.Configuration>
{
public override void InitializeDatabase(MyDbContext context)
{
bool exists = context.Database.Exists();
base.InitializeDatabase(context);
if (!exists)
{
MyDbSeed.Seed(context);
}
}
}
Note that Migrations.Configuration is a class generating by migration command line in Package Manager Console. You may need to change internal to public modifier of the Migrations.Configuration class.
And register it from your OmModelCreating:
public partial class MyDbContext : DbContext
{
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
Database.SetInitializer<MyDbContext>(new MyDbContextInitializer());
//other code for creating model
}
}
回答27:
Here I want to share another method that prevent the error of model backing when context changed is:
1) Open your DbContext File
2) Add namespace using Microsoft.AspNet.Identity.EntityFramework;
3)
public MyDbContext() : base(\"name=MyDbContext\")
{
Database.SetInitializer(new DropCreateDatabaseAlways());
}