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




entity-framework-4 code-first (18)

错误消息:

“创建数据库后,支持”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”,当我尝试将联系人对象添加到上下文时发生错误。 我在这里错过了什么吗?


以下是Jeff发布的关于实际发生的事情的一些信息:

对于那些看到这个例外的人:

“创建数据库后,支持”Production“上下文的模型已经发生了变化,无论是手动删除/更新数据库,还是使用IDatabaseInitializer实例调用Database.SetInitializer 。”

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

首次创建模型时,我们运行DatabaseInitializer来执行诸如创建数据库(如果数据库不在其中或添加种子数据)的操作。 默认的DatabaseInitializer尝试将使用模型所需的数据库模式与存储在使用数据库创建的EdmMetadata表中的模式的散列(比如Code First创建数据库时)进行比较。 现有的数据库将不具有EdmMetadata表,因此不会有哈希值......如果该表丢失,则今天的实现将抛出。 因为它是默认版本,所以我们将在我们提供该版本之前改变这种行为。 在此之前,现有的数据库通常不需要任何数据库初始化程序,因此可以通过调用以下方式关闭您的上下文类型:

Database.SetInitializer<YourDbContext>(null);

杰夫


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

我有数据库第一个EF,并在同一时间使用asp.net身份

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

因此首先DROP手动/从脚本创建的所有asp.net标识表。

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

刚刚发现了答案并想在此更新。 只需要执行以下操作。

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

只需在SQL Server Management Studio中运行followng sql命令:

delete FROM [dbo].[__MigrationHistory]

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

1)打开你的DbContext文件

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

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


对于Entity Framework 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);

是的,马特弗雷尔是正确的。 UPDATE -EDIT:警告我同意其他人的意见,而不是将此代码添加到global.asax添加到您的DbContext类

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

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

目前我正在使用Entity Framework 6.1.3 / .NET 4.6.1


对于我来说,随着升级到4.3.1,我只是截断EdmMetaData表或直接删除它。


尝试使用属于使用System.Data.Entity的数据库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);
    }

}

我也在阅读Pro ASP.NET MVC 4书籍,并遇到了同样的问题。 对我而言,在本书的“添加模型验证”部分中做出更改后,我开始遇到问题。 我解决问题的方法是将我的数据库从localdb移动到全面的SQL Server 2012服务器。 (顺便说一句,我知道我很幸运,我可以切换到完整的版本,所以不要恨我;-)))必须有一些与数据库的沟通是导致问题。


我使用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

        }

我花了很多天的时间来解决这个问题,分析了许多不同的帖子,并尝试了很多选择, 最后修复。 这2个项目在我的解决方案中使用EF代码第一次迁移:

  • 控制台应用程序“DataModel”,主要使用包含所有我的代码第一个实体,DbContext,Mirgations和通用存储库的程序集。 为了能够从软件包管理器控制台生成迁移,我在该项目中包含了单独的空本地数据库文件(位于DataModel / App_Data文件夹中)。
  • WebApi,它引用DataModel项目并使用来自WebApi / App_Data文件夹的本地数据库文件,但未包含在项目中

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

我的环境:

  • Windows 8.1 x64
  • 带更新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生成与数据库对应的正确的代码优先实体和上下文,Project - > Add New Item - > ADO.NET Entity Data Model - > Code First from database: 当然,作为替代方案,如果您没有数据库,则可以手动编写模型(代码优先实体和上下文),然后生成初始迁移和数据库。
  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. 在使用软件包管理器控制台之前,请确保您使用正确的数据库进行更新或生成迁移,并将需要的项目设置为解决方案的启动项目。 为了连接到数据库,它将使用该.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. 通过启动项目重新创建数据库(将执行上面的行)或使用软件包管理器控制台“update-database”命令。
    4. 手动检查生成的数据库和__MirgationHistory是否对应于最新的迁移脚本。

我遇到了这个问题,结果发现一个项目指向了SQLExpress,但是有问题的那个指向了LocalDb。 (在他们各自的web.config中)。 愚蠢的监督,但值得注意的情况下,以防其他人解决这个问题。


检查以下步骤

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

2。

  1. 您的Context类名称应匹配并检查它

此修补程序在CTP5之后不再有效。

你必须做Database.SetInitializer<YourContext>(null);


然而,好的建议在所有情况下都非常准确。 我想出一个。 请确保在Visual Studio中使用PM窗口运行“enable-migrations”,然后将Migration文件夹添加到您的项目中。

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

如果你有全部的解决方案,并且需要部署publis。

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


现在是:

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

在YourDbContext.cs文件中。


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

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#specifichttps://msdn.microsoft.com/en-us/data/jj591621.aspx#specific


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







code-first