支持上下文的模型自数据库创建以来就发生了变化,在创建DB之后立即发生变化

本文关键字:创建 变化 DB 之后 模型 上下文 数据库 支持 发生了 | 更新日期: 2023-09-27 18:12:53

我正在做一个项目,使用实体框架4.1将我们的各种对象持久化到数据库(代码优先)。

我在Visual Studio测试与本地SQL Express DB,我们的詹金斯服务器部署提交的代码到测试服务器。当发生这种情况时,我临时更改本地连接字符串以指向测试DB服务器,并运行单元测试以重新创建测试数据库,以便它与我们最新的实体相匹配,等等。

我最近注意到我们的测试服务器给出这个错误:

支持'EntityFrameworkUnitOfWork'上下文的模型自数据库创建以来已经更改。要么手动删除/更新数据库,要么调用database。使用IDatabaseInitializer实例设置初始化器。例如,DropCreateDatabaseIfModelChanges策略将自动删除和重新创建数据库,并可选择使用新数据播种。

这通常表明我们的代码已经更改,我需要运行单元测试来重新创建数据库。但我刚刚做了!我不认为我们的部署过程有什么问题——测试服务器上的dll似乎与我本地环境中的版本相同。是否有任何其他设置或环境因素可能导致自创建数据库以来模型已更改的错误?

我是新来的,谢谢你的帮助!

支持上下文的模型自数据库创建以来就发生了变化,在创建DB之后立即发生变化

您看到的错误表示存储在EdmMetadata表中的模型哈希值与从应用程序中的模型计算的模型哈希值不同。因为您正在从不同的应用程序(您的dev.应用程序)运行数据库创建,所以这两个应用程序可能不同。这里的简单建议是:不要使用不同的应用程序创建数据库,而是让您的主应用程序创建数据库(自动或例如使用一些管理界面)。

作为另一个选项,您应该能够通过删除负责这些检查的约定来完全关闭此检查:

modelBuilder.Conventions.Remove<IncludeMetadataConvention>();

模型哈希计算依赖于应用程序中的当前实体(任何简单的更改都会导致不同的模型哈希)和数据库服务器版本/清单。例如,在SQL server 2005和2008上部署的模型将具有不同的模型散列(Express与Full或2008与2008 R2不应该导致不同的模型散列)。

这可能是由于不同平台之间的反射顺序不同而导致的。为了验证,您可以使用EdmxWriter API来比较来自两个环境的EDMX。如果任何一个表有不同的列顺序,那么这就是问题。

要解决这个问题,您可以更改测试数据库更新的方式,这样它就可以从您的测试服务器而不是您的本地机器更新。

我们将在下一个版本中修复这个问题。

在代码优先的方法中,在代码执行期间生成SSDL。生成的wsdl中包含的信息之一是DbConnection中使用的提供程序的名称。正如您所说,您要连接到不同的数据库引擎,因此必须使用两个不同的提供程序。这完全改变了哈希函数的输出。

下面的代码是从EntityFramework程序集中提取出来的:

using (XmlWriter writer = XmlWriter.Create(output, settings))
{
    new SsdlSerializer().Serialize(database, providerInfo.ProviderInvariantName, providerInfo.ProviderManifestToken, writer);
}

这可能会有帮助,链接到Scott G的博客肯定会解决你的问题,看看这个问题链接

编辑1:这是Scott G博客的链接 编辑2:如果您首先在集成服务器上使用数据库,您也可以检查这一点

编辑3:这是一个更详细的答案,就像Scott G

运行您的应用程序的两个服务器运行不同的操作系统(或服务包?)似乎使用的SHA256CryptoService可以抛出一个PlatformNotSupportedException,导致它回退到另一个方法。

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;
}

您可以通过在每个服务器上使用反射调用以下2个(内部/私有)方法来测试这一点。

MetaDataWorkspace.ToMetadataWorkspace(DbDatabaseMapping, Action<string>)
CodeFirstCachedMetadataWorkspace.ComputeSha256Hash(string xml);

实体框架代码首先创建一个名为EdmMetadata的表。它保存当前模型的散列。一旦你运行应用程序,EF会检查所使用的模型是否与数据库"知道"的模型相同。

如果你想执行数据库迁移,我建议你首先使用EF Code迁移,尽管它仍然是alpha版本。

如果您不想使用迁移,您可以:

手动处理模式更改—这意味着将EdmMetadata表的内容与所有更改一起移动到测试服务器

将db初始化器设置为DropCreateDatabaseIfModelChanges(或者更好的是从它派生的东西,并使用Seed()方法来写入初始数据)。要设置初始化器,可以在应用程序启动时调用Database.SetInitializer()或使用appSettings

<add key="DatabaseInitializerForType Fully.Qualified.Name.Of.Your.DbContext," value="Fully.Qualified.Name.Of.The.Initializer" />

我只是不小心重命名了我的。mdf文件并得到了这个错误。看一下这个