EF Code First thinks database is out of date -- only in production
I have an ASP.NET MVC 3 app that is using SQL Server CE 4.0 and Entity Framework 4.1 Code First. It works fine locally, but in production, it fails with the following er开发者_运维百科ror:
The model backing the 'foobar' 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.
I've verified that my application dll and database file are up-to-date on the remote server, but I continue to get this error.
Any idea what the problem could be?
Note: I'm using the RTF version of the Entity Framework 4.1, not CTP.
Edit
Okay, if I delete the EdmMetadata table, and re-publish the database to the production server, I no longer get the error. However, I completely don't understand why I should have to do this. The model has not changed. It hasn't changed in weeks, and I rebuilt the database just today. I guess the key to this whole thing is the hash. What is the EdmMetadata hash being compared against?
Edit 2
According to Mark S's answer, the hash in the EdmMetadata table is compared against a hash of the SSDL. However, there is no actual SSDL file (no file with extension .ssdl and no file containing "ssdl") anywhere in the solution. So, where is the SSDL actually stored? Is it generated at design time or run time?
Edit 3
To answer my own question, SSDL does get generated and cached at runtime (more details here), but looking at the actual schema of SSDL, I'm not sure I see anything that could possibly change simply because the project's DLL lives in a different location on a different server.
Note: I'm using the exact same database file (.sdf) for test and production. I'm literally ftp-ing the file from bin/App_Data to the App_Data folder on the production server. I'm also ftp-ing the project DLL. So, the only thing that should be different between test and production is that these files live in a different place.
Also, just for the record, here is my connection string:
DataSource=|DataDirectory|foobar.sdf" providerName="System.Data.SqlServerCe.4.0
Edit 4 (final edit?)
The problem turned out to be a DLL issue. I think a different version of the EntityFramework DLL was being used remotely vs. locally. The solution was to make sure I had the latest version of EF 4.1 (RTW), clear and re-add references, regenerate the database, and re-publish. Everything is now working great.
In response to "What is the EdmMetadata hash being compared against?"
The EdmMetadata table allows Code First to determine if the model in your code is the same as the model in your database. The table contains a single row which is a hash of your SSDL. SSDL stands for Store Schema Definition Language and is an XML based language used to describe an Entity model and the mappings between models.
You can read more about SSDL and view the specification at http://msdn.microsoft.com/en-us/library/bb399559.aspx
You mention that things work fine locally but not in production. Are you allowing Code First to build both the local and production databases? Is the production database already existing or being generated in another fashion?
CodeFirst is reporting that the hash in the database doesn't match the present model's hash so something must be different. Figuring out what may be a challenge.
The EdmMetadata table is mapped to the EdmMetadata class. There is a TrygetModelHash method in this class which you can use to get the hash for a given context. If you're desparate you could use this to compare your current model to the hash that's in your production database. This would at least keep you from having to build a new database constantly just for testing.
You can also instruct Code First to exclude the EdmMetadata table if desired.
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<IncludeMetadataConvention>();
}
Disable validation:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<IncludeMetadataConvention>();
}
Check out this video:
http://www.pluralsight-training.net/microsoft/players/PSODPlayer.aspx?author=scott-allen&name=mvc3-building-data-i&mode=live&clip=0&course=aspdotnet-mvc3-intro
This is part of the free plural sight training available on http://asp.net/mvc. Click the "When Classes Change" video on the left side of the page, then go to 8:30 in the video.
Apparently if you delete the EDMMetadata
table in the DB, EF will disable model validation.
精彩评论