24

I am working on a project which uses Entity Framework 4.1 for persisting our various objects to the database (code first).

I am testing in Visual Studio with a local SQL Express DB, and our Jenkins server deploys committed code to a testing server. When this happens I temporarily change my local connection string to point to the testing DB server and run a unit test to re-create the test database so that it matches our latest entities, etc.

I've recently noticed our testing server is giving this error:

The model backing the 'EntityFrameworkUnitOfWork' 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.

This is usually an indication that our code has changed and I need to run the unit test to re-create the database. Except I just did that! I don't believe there is anything wrong with our deployment process - the DLLs on the test server seem to be the same versions as in my local environment. Are there any other settings or environment factors that can cause this error about the model having changed since the database was created?

I'm new here - thanks for any help!

DaveBeta
  • 447
  • 1
  • 5
  • 11
  • 1
    Could you use the method `System.Data.Entity.Infrastructure.EdmMetadata.TryGetModelHash(YourDbContext)` to get the ModelHash and try that on your local PC and the testserver to see if they are different? – Marc Dec 16 '11 at 00:37
  • Did you run custom tool in order to regenerate context or POCO after you regenerated database ? – radu florescu Dec 16 '11 at 08:02
  • 1
    @Marc Yes the hashes do seem to be different. – DaveBeta Dec 19 '11 at 17:28
  • @Floradu88 Not 100% sure what you mean. I used Database.SetInitializer with DropCreateDatabaseAlways DBContext to regenerate the DB. I guess that would be POCO? – DaveBeta Dec 19 '11 at 17:31

7 Answers7

25

The error you see means that the model hash stored in EdmMetadata table is different from the model hash computed from the model in the application. Because you are running database creation from a different application (your dev. application) it is possible that those two differ. Simple advice here is: don't use different applications for database creation and instead let your main application create the database (either automatically or for example with some admin interface).

As another option you should be able to turn off this check completely by removing the convention responsible for these checks:

modelBuilder.Conventions.Remove<IncludeMetadataConvention>();

Model hash computation is dependent on current entities in your application (any simple change result in different model hash) and on database server versions / manifest. For example a model deployed on SQL server 2005 and 2008 will have different model hash (Express vs. Full or 2008 vs. 2008 R2 should not result in different model hash).

Gilles
  • 5,269
  • 4
  • 34
  • 66
Ladislav Mrnka
  • 360,892
  • 59
  • 660
  • 670
  • We've got a different OS version on the desktop and server, and we also have a couple of different versions of SQL Server because I'm using SQL Express locally but not on UAT. If its just a fact of life that these platform differences will cause a different `EdmMetadata` hash, I am happy to simply disable the hash creation/checking by removing the convention. Thanks! – DaveBeta Dec 19 '11 at 17:25
  • `Warning 2 'System.Data.Entity.Infrastructure.IncludeMetadataConvention' is obsolete: 'The IncludeMetadataConvention is no longer used. EdmMetadata is not included in the model. is now used to detect changes in the model.' ` **2013** Answer is no longer relevant in EF4 – Piotr Kula Mar 07 '13 at 10:05
  • @ppumkin: Answer was relevant prior to EF4.3 – Ladislav Mrnka Mar 07 '13 at 10:06
  • Anyone got an update for EF5.0 or Database/Model first scenarios? (similar to this question http://stackoverflow.com/questions/16459047/code-first-view-generation-generating-different-hash-values) – Dave A-W Nov 21 '13 at 03:25
9

This can happen due to reflection ordering differences across different platforms. To verify, you can use the EdmxWriter API to compare the EDMX from both environments. If any of the tables have different column ordering, then this is the issue.

To workaround, you can change the way your test database gets updated such that it is updated from your test server rather than your local box.

We are going to fix this issue in the next release.

Andrew Peters
  • 11,135
  • 4
  • 37
  • 34
6

In the code-first approach, the SSDL is generated during the execution of the code. One of the informations included in the generated SSDL is the name of the provider used in the DbConnection. As you said, you're connecting to different databases engines, so you must use two different providers. This completly changes the output of the hashing function.

The below code was extracted from the EntityFramework assembly:

using (XmlWriter writer = XmlWriter.Create(output, settings))
{
    new SsdlSerializer().Serialize(database, providerInfo.ProviderInvariantName, providerInfo.ProviderManifestToken, writer);
}
Sergey Berezovskiy
  • 232,247
  • 41
  • 429
  • 459
Diego Frata
  • 1,028
  • 7
  • 15
3

This might help and the link to Scott G blog will sure be a solution to your problem check this question link

Edit 1: this is the link to Scott G blog

Edit 2: You may also check this if you use a database first on integration server

Edit 3: This is a more detailed answer like the one from Scott G

Community
  • 1
  • 1
radu florescu
  • 4,315
  • 10
  • 60
  • 92
3

Are the two servers running your application running different operating systems (or service packs?) It appears the SHA256CryptoService used can throw a PlatformNotSupportedException which causes it to fallback to another method.

http://msdn.microsoft.com/en-us/library/system.security.cryptography.sha256cryptoserviceprovider.sha256cryptoserviceprovider.aspx

// System.Data.Entity.Internal.CodeFirstCachedMetadataWorkspace
private static SHA256 GetSha256HashAlgorithm()
{
  SHA256 result;
  try
  {
    result = new SHA256CryptoServiceProvider();
  }
  catch (PlatformNotSupportedException)
  {
    result = new SHA256Managed();
  }
  return result;
}

You may be able to test this by using reflection to invoke the following 2 (internal/private) methods on each server.

MetaDataWorkspace.ToMetadataWorkspace(DbDatabaseMapping, Action<string>)
CodeFirstCachedMetadataWorkspace.ComputeSha256Hash(string xml);
Betty
  • 9,109
  • 2
  • 34
  • 48
2

Entity Framework code first creates a table called EdmMetadata. It keeps a hash of your current model. Once you run the application EF checks if the model being used is the same as the model that the db 'knows about'.

If you want to perform database migration, I suggest you use EF Code first migrations though it's still an alpha.

If you don't want to use migrations you can either:

handle the schema change manually - that means moving the content of the EdmMetadata table to the test server along with all the changes

or

set the db initializer to DropCreateDatabaseIfModelChanges (or better something derived from it and use the Seed() method to write the initial data). To set the initialzer either call Database.SetInitializer() on application start or use the appSettings

<add key="DatabaseInitializerForType Fully.Qualified.Name.Of.Your.DbContext," value="Fully.Qualified.Name.Of.The.Initializer" />
Chris
  • 12,192
  • 5
  • 21
  • 23
  • 1
    Thanks for that. My mystery was more around the fact that I have 2 application servers which as far as I can tell are identical - certainly the DLLs are identical, and yet they both seem to think the DB created by the other is "different". I have found that just by deleting the EdmMetadata table I can suppress the error and both applications seem to be working with the same database happily. This seems wrong! – DaveBeta Nov 29 '11 at 18:40
  • i'm having a similar problem at deploy time, a simple recompile and redeploy of the dll (absolutely no changes) and it fixes the problem – JarrettV Dec 15 '11 at 22:14
0

I only accidentally renamed my .mdf file and got this error. So look also for this.