自创建数据库以来,支持<Database>上下文的模型已更改


253

错误消息:

“自创建数据库以来,支持'AddressBook'上下文的模型已更改。要么手动删除/更新数据库,要么使用IDatabaseInitializer实例调用Database.SetInitializer。例如,RecreateDatabaseIfModelChanges策略将自动删除并重新创建数据库,并且(可选)用新数据作为种子。”

我正在尝试使用代码优先功能,以下是我写的内容:

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

上下文类:

public class AddressBook : DbContext
{
    public AddressBook()
    { }
    public AddressBook(DbModel AddressBook)
        : base(AddressBook)
    {

    }
    public DbSet<Contact> contacts { get; set; }
    public DbSet<Address> Addresses { get; set; }
}

和连接字符串:

<?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>

因此,数据库名称为“ AddressBook”,并且在尝试将联系人对象添加到上下文时发生错误。我在这里想念什么吗?



从您的数据库中删除__MigrationHistory表
Zahid Hasan

Answers:


397

现在是:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    Database.SetInitializer<YourDbContext>(null);
    base.OnModelCreating(modelBuilder);
}

在YourDbContext.cs文件中。


我已经手动更改了生产数据库并关闭了迁移功能,因此可以正常运行,谢谢
Mohsen Afshin 2012年

13
附言

48
比Global.asax更好的是将其放在DbContext类的构造函数中。这样,它适用于使用上下文的每个站点,而不只是适用于Global.asax文件控制的一个站点。
科林2013年

7
最好将其放在上下文类的静态构造器中,因此只能调用一次-如本示例视频所示:msdn.microsoft.com/en-us/data/jj572367
Christian Fredh 2013年

3
应该将其放置在受保护的覆盖内部。void OnModelCreating(DbModelBuilder modelBuilder){Database.SetInitializer <YourDbContext>(null); base.OnModelCreating(modelBuilder); }
克里斯·冯

135

以下是Jeff发布的Scott Gu的博客中有关实际情况的一些信息:

对于那些看到此异常的人:

“自创建数据库以来,支持'生产'上下文的模型已更改。可以手动删除/更新数据库,或Database.SetInitializer使用IDatabaseInitializer实例进行调用。”

这是正在发生的事情以及如何处理:

首次创建模型时,我们运行DatabaseInitializer进行诸如创建数据库(如果数据库不存在)或添加种子数据之类的操作。默认的DatabaseInitializer尝试将使用模型所需的数据库架构与存储在使用数据库创建的EdmMetadata表中的架构的哈希值进行比较(当Code First是创建数据库的数据库时)。现有的数据库将没有EdmMetadata表,因此也将没有哈希表……如果缺少该表,今天的实现将被抛出。由于它是默认版本,因此在发布最终版本之前,我们将努力更改此行为。在此之前,现有数据库通常不需要任何数据库初始化程序,因此可以通过调用以下上下文类型将其关闭:

Database.SetInitializer<YourDbContext>(null);

杰夫


9
我今天尝试了此操作,但不再得到“模型已更改”,而是得到“无效的对象名称'dbo.Table'”
Stefan Bergfeldt

3
Jeff希望这是一种解决方法,但是已经过去了两年多,并且仍然需要将SetInitializer设置为null。对?所以有人可以解释一下它如何适合迁移工作流程。
kroiz 2014年

2
@jakejgordon:EF6也是如此,但是如果它在Global.asax中,它只能在运行网站时解决问题。如果您有单元测试,那么您就是OOL。最好将其放在YourDbContext的构造函数中。这样就可以修复每个项目,包括网站和测试项目。
2014年

1
IMO,这个答案应该得分更高,因为它实际上解释了为什么我们需要添加这一行代码。谢谢。
Paul

1
@StefanBergfeldt,如果您或任何人得到Invalid object name 'dbo.Table检查,请检查您的连接字符串attachDbFilename和初始目录
benscabbia

41

对于实体框架5.0.0.0-6.1.3

不要确实要做到以下几点:

1. using System.Data.Entity;   to startup file (console app --> Program.cs / mvc --> global.asax
2. Database.SetInitializer<YourDatabaseContext>(null);

是的,Matt Frear是正确的。更新-编辑: 警告是我同意其他观点,而不是将此代码添加到添加到DbContext类的global.asax中

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    // other code 
    Database.SetInitializer<YOURContext>(null);
    // more code here.
}

正如其他人提到的那样,这对于处理单元测试也很有益。

目前,我正在将它与Entity Framework 6.1.3 /.net 4.6.1结合使用

我将在不久的将来再次提供CORE片段。


1
谢谢!Program.cs绝对适用于控制台。
HockeyJ 2014年

但是,当您第一次初始化数据库时,如果我在onModelCreating方法中将setinitializer null设置为null,则它不会创建数据库。有什么想法吗 ?我应该使用(var context = Activator.CreateInstance <TContext>()){context.Database.Initialize(true); }
Rupesh Kumar Tiwari 2015年

我需要找到我会用到的代码,有时我会注释掉一行并交换。。。我不记得这个问题了,我需要看看。
汤姆·斯蒂克

1
最好的解决方案。它导致我的解决方案运行,并且我不知道后果是什么。提交和部署。
Svend


31

CTP5之后,此修复程序不再起作用。

你所要做的 Database.SetInitializer<YourContext>(null);


1
哪里是去... OnModelCreating有一个名为DbDatabase没有访问
詹姆斯雷亚特吉

在启动的某个地方,我在Application_Start中设置了我的。
chrisortman

Database.SetInitializer在EF 4.3最终版本中似乎可以正常工作。
理查德·贝尔

我认为“此修复程序在CTP5之后不再起作用”意味着他在说2010年8月30日以来的“已接受”答案。
汤姆·斯蒂克

19

刚刚在这里找到答案和更新想法。只需要执行以下操作。

public class AddressBook: DbContext
{
   protected override void OnModelCreating(ModelBuilder modelBuilder)
   {
    modelBuilder.IncludeMetadataInDatabase = false;
   }
}

12
更高版本的EF不再可能modelBuilder.Conventions.Remove<IncludeMetadataConvention>();这样做,也无济于事。DbDatabase.SetInitialzer(null); 确实有效。
JTew 2012年

@TomStickel-我同意。将stackoverflow.com/a/6143116/255562标记为答案。
Ashish Gupta

16

或者,您可以将此行放在Application_Start()下的Global.asax.cs文件中:

System.Data.Entity.Database.SetInitializer(new System.Data.Entity.DropCreateDatabaseIfModelChanges<ProjectName.Path.Context>());

确保将ProjectName.Path.Context更改为您的名称空间和上下文。如果首先使用代码,则每当对架构进行任何更改时,它将删除并创建一个新数据库。


正是我需要的,因为我只是在做原型。非常感谢。
学习者2014年

8

我花了很多天解决这个问题,分析了许多不同的帖子,尝试了许多选择,最后解决了。 我的解决方案中的这2个项目是使用EF代码优先迁移的:

  • 控制台应用程序“ DataModel”,主要用作程序集,其中包含我的所有代码优先实体,DbContext,Migration和通用存储库。我已经在该项目中包括了单独的空本地数据库文件(位于DataModel / App_Data文件夹中),以便能够从Package Manager控制台生成迁移。
  • WebApi,它引用DataModel项目并使用WebApi / App_Data文件夹中的本地数据库文件,该文件不包含在项目中

请求WebApi时出现此错误...

我的环境:

  • Windows 8.1 x64
  • 带有Update 1的Visual Studio 2015 Professional
  • 我所有针对.NET Framework 4.6.1的项目
  • NuGet的EntityFramework 6.1.3

在这里,我收集了您应注意的所有备注以及必须满足的所有条件/要求,以避免提及的异常:

  1. 您应仅将一个版本的EntityFramework Nuget包用于解决方案中的所有项目。
  2. 通过依次运行所有迁移脚本创建的数据库应具有与目标数据库相同的结构/架构,并与实体模型相对应。以下三件事必须彼此完全对应/反射/匹配:
    • 您所有的迁移脚本到最后
    • 当前代码优先实体模型状态(DbContext,实体)
    • 目标数据库
  3. 目标数据库(mdf文件)应更新/对应到上一个迁移脚本。验证目标数据库中的“ __MigrationHistory”表是否包含您拥有的所有迁移脚本的记录,这意味着所有迁移脚本已成功应用于该数据库。我建议您使用Visual Studio生成与您的数据库相对应的正确的代码优先实体和上下文,项目->添加新项-> ADO.NET实体数据模型->从数据库优先代码: 当然,如果您没有数据库,可以手动编写模型(编码第一个实体和上下文),然后生成初始迁移和数据库。
  4. 连接字符串的名称,例如启动项目(Web.config / App.config)的配置文件中的MyConnectionString

    <configuration>
      <connectionStrings>
        <add name="MyConnectionString" connectionString="...">
      </connectionStrings>
    <configuration>

    应该等于在DbContext的构造函数中传递的参数:

     public partial class MyDbContext : DbContext
     {
        public MyDbContext()
           : base("name=MyConnectionString"){}
        ...
  5. 在使用Package Manager Console之前,请确保使用正确的数据库进行更新或生成迁移,并且将所需项目设置为解决方案的启动项目。为了连接数据库,它将使用该.config文件中的连接字符串,该文件在项目中设置为启动项目。
  6. 最主要的是,它解决了我的问题:这很奇怪,但是在我的WebApi / bin文件夹中,DataModel.exe很旧,自上次构建以来未刷新。由于迁移嵌入在我的程序集DataModel.exe中,因此我的WebApi使用旧的镜像更新了数据库。我很困惑,为什么在WebApi中更新数据库后,它不对应于DataModel的最新迁移脚本。以下代码自动在我的WebApi / App_Data文件夹中创建(如果不存在)或更新到最新的迁移本地数据库。

       public class WebApiApplication : System.Web.HttpApplication
       {
           protected void Application_Start()
           {
               Database.SetInitializer(new MigrateDatabaseToLatestVersion<ODS_DbContext, Configuration>()); 
               ...

    我尝试过清理并重建解决方案,但没有帮助,因为我从WebApi中完全删除了bin和obj文件夹,从WebApi / App_Data中删除了数据库文件,构建,重新启动了WebApi,向其提出了请求,它创建了正确的数据库-延迟初始化(使用上面的行),它对应于最新的迁移,并且没有出现更多异常。 因此,这可能会解决您的问题:

    1. 从启动项目中手动删除bin,obj文件夹(该文件夹会生成/更新数据库)
    2. 构建您的启动项目,或者更好地清理和重建所有解决方案。
    3. 通过启动项目(将在上面执行行)来重新创建数据库,或使用Package Manager Console的“ update-database”命令。
    4. 手动检查生成的db和__MirgationHistory是否对应于最新的迁移脚本。

5

对我来说,升级到4.3.1后,我只是截断了EdmMetaData表或直接将其删除。


我更新到4.3.1,然后将其重命名为EdmMaetaData表。现在,我可以根据需要对模型进行更改,而不再有关于模型支持等等的烦人的错误消息。
Ashok Padmanabhan 2012年

3

对于VB.NET开发人员:

在方法Application_Start()的末尾,将以下行添加到Glabal.asax.vb文件中

Database.SetInitializer(Of ApplicationDbContext)(Nothing)

将ApplicationDbContext更改为您特定的Db上下文。


2

我遇到了这个问题,结果发现一个项目指向SQLExpress,但是一个有问题的项目指向LocalDb。(在各自的web.config中)。愚蠢的监督,但在此值得注意,以防其他人对这个问题进行故障排除。


2

这意味着上下文中有一些尚未执行的更改。请首先运行Add-Migration以生成我们已完成的更改(我们可能不知道的更改),然后运行Update-Database


2

我遇到了同样的问题-重新添加迁移和更新数据库无法正常工作,上述所有答案似乎都不对。然后灵感就袭来了-我使用了多个层次(一个网络,一个数据和一项业务)。数据层具有上下文和所有模型。Web层从不抛出此异常-它是业务层(我将其设置为用于测试和调试的控制台应用程序)。事实证明,业务层没有使用正确的连接字符串来获取数据库并创建上下文。因此,我将连接字符串添加到业务层(和数据层)的应用程序配置中,并且中提琴可以正常工作。将其放在此处给其他可能遇到相同问题的人。


1

我使用Database.CompatibleWithModel方法(在EF5中可用)在使用模型之前测试模型和数据库是否匹配。我在创建上下文后立即调用此方法...

        // 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

        }

1

好的建议,但是,在所有情况下都如此准确。我知道了。请确保使用Visual Studio中的PM窗口运行“启用迁移”,并且“迁移”文件夹将添加到您的项目中。

确保添加到的文件夹中的两个c#类文件将包含您的所有模型及其各自的属性。

如果具备构建解决方案的全部功能,则可以发布以进行部署。

逻辑是现有的元数据不能被覆盖,因为您的应用程序没有元数据来替换当前元数据。结果,您得到此错误“自创建数据库以来,支持上下文的模型已更改”


1

以防万一有人和我有相同的情况。

我有数据库第一个EF,同时使用asp.net标识

所以我的webconfig中有两个connectionStrings,这没有问题。碰巧我创建/运行了脚本以手动生成我不应该生成的asp.net身份表。

因此,首先删除/手动/从脚本创建的所有asp.net身份表。

DROP TABLE __MigrationHistory
DROP TABLE AspNetRoles
DROP TABLE AspNetUserClaims
DROP TABLE AspNetUserLogins
DROP TABLE AspNetUserRoles
DROP TABLE AspNetUsers

1

这些解决方案均不适用于我们(除了完全禁用模式检查之外)。最后,我们的Newtonsoft.json版本出现了不匹配的情况

我们的AppConfig没有正确更新:

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

解决方案是将程序集版本更正为我们实际部署的版本

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

我们在Newtonsoft.json的版本中遇到了类似的问题,当我们更新版本时,问题就解决了。
Rui Estreito

0

在对该主题进行了一些研究之后,我发现如果您先前在本地sql server express上创建了db实例,则基本上会发生该错误。因此,只要您对db进行更新,并尝试更新db /在db上运行一些代码,而无需Update Database使用Package Manager Console;首先,您必须手动删除我们本地SQL Express上的先前数据库。

此外,除非您AutomaticMigrationsEnabled = false;的配置中没有,否则此解决方案都有效。

如果您使用版本控制系统(git,svn等),并且其他一些开发人员在生产阶段更新db对象,则每当您更新代码库并运行应用程序时,都会出现此错误。

如上所述,有一些基于代码的解决方案。但是,对于某些情况,这是最实用的一种。


0

我也在阅读Pro ASP.NET MVC 4书,遇到了同样的问题。对我而言,在进行本书的“添加模型验证”部分中规定的更改后,我开始遇到问题。解决问题的方法是将数据库从localdb移动到功能齐全的SQL Server 2012服务器。(顺便说一句,我知道我很幸运,我可以切换到完整版本,所以请不要讨厌我。;-)))与数据库的通信中一定有引起问题的信息。


您怎么知道它是与数据库的通信,而不是它的元数据?
flup

2
回复晚了非常抱歉。事实证明,这根本不是沟通问题!重新创建数据库只是掩盖了问题,因为我又遇到了同样的问题!ef创建了一个__Migrationxxx(无法记住表的确切名称,因为我刚刚删除了它)。只需删除它,一切都会很好。
J3

@ MyJ3所有的人都在吐槽所有这些friggin行和代码行。这就是我所需要的!应该作为答案(可选方案)。
Terrance00

@ Terrance00谢谢!
J3S

0

请按照以下步骤检查

  1. Database.SetInitializer(null); ->在Global.asax.cs中

2。

  1. 您的Context类名称应与check匹配

0

修改Global.asax.cs,包括Application_Start事件:

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

5
就个人而言,我会对此有所了解。
Casey 2014年

3
否否否,我不想在99%的时间内使用DropCreateDatabaseIfModelChanges!
汤姆·斯蒂克

0

此错误可能表明您的连接字符串存在问题,以及您的连接字符串名称是否与数据库上下文声明匹配。

我有此错误,因为我错误地命名了本地数据库(错误的错误),并且“ DefaultConnection”的web.config中的连接字符串名称与MyDbContext不匹配,即

public MyDbContext(): base("DefaultConnection")
{}


<connectionStrings>
    <add name="DefaultConnection" ...
  </connectionStrings>

0

尝试使用属于System.Data.Entity的Database SetInitializer;

在Global.asax中

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

每次更改模型时都会创建一个新的数据库。但是您的数据库将为空。为了填充虚拟数据,可以使用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);
    }

}

0

很奇怪,但是这里的所有答案对我来说都没有用。对我来说工作初始化器

MigrateDatabaseToLatestVersion

这是我的解决方案(我知道,这可能要简单得多,但这是我的用法):

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只是从DropCreateDatabaseAlways继承而来,因此在某些特定情况下(测试),将重建整个数据库。否则,它将迁移到最新版本。

我的来源:https : //msdn.microsoft.com/en-us/data/jj591621.aspx#specific


0

当我们将一个数据库用于两个应用程序时,我遇到了同样的问题。disableDatabaseInitialization="true"在上下文类型部分中进行设置对我有用。

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

查看更多详细信息https://msdn.microsoft.com/en-us/data/jj556606.aspx


0

创建自定义上下文初始化程序:

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

请注意,Migrations.Configuration是程序包管理器控制台中由迁移命令行生成的类。您可能需要将Migrations.Configuration类的internal更改为public。

并从您的OmModelCreating中注册:

public partial class MyDbContext : DbContext
{

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        Database.SetInitializer<MyDbContext>(new MyDbContextInitializer());

        //other code for creating model
    }
}

-1

在这里,我想分享另一种防止上下文更改时发生模型支持错误的方法:

1)打开您的DbContext文件

2)使用Microsoft.AspNet.Identity.EntityFramework添加名称空间;

3)public MyDbContext():base(“ name = MyDbContext”){Database.SetInitializer(new DropCreateDatabaseAlways()); }

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.