实体框架告诉我支持上下文的模型已经改变

时间:2015-02-26 16:25:40

标签: entity-framework ef-migrations

我对Entity Framework代码首次迁移有一个奇怪的问题。几个月以来,我一直在使用EF和代码首次迁移项目,事情进展顺利。我最近创建了一个新的迁移,当运行Update-Database恢复的数据库备份时,我收到此错误:

  

支持上下文的模型自数据库以来已发生变化   创建。考虑使用Code First Migrations来更新数据库

迁移执行如下操作:

public override void Up()
{
    using (SomeDbContext ctx = new SomeDbContext())
    {
        //loop through table and update rows
        foreach (SomeTable table in ctx.SomeTables)
            table.SomeField = DoSomeCalculation(table.SomeField);

        ctx.SaveChanges();
    }
}

我没有使用Sql()函数,因为DoSomeCalculation必须在C#代码中完成。

通常当我得到类似这样的东西意味着我以某种方式更新了我的模型并忘记创建迁移。然而,这次并非如此。奇怪的是,错误甚至不是我几天前创建的迁移,并且工作正常。

我看了quite一些关于articles this based on this article)的问题,他们似乎都在说电话

Database.SetInitializer<MyContext>(null);

这样做确实有效,但我的理解({{3}}是这样做会消除EF确定数据库和模型何时不同步的能力。我不想这样做。我只是想知道它为什么认为它们突然不同步。

我还尝试运行Add-Migration,看看它是否认为模型有什么变化,但它不会让我这样做,说明我有待运行的待迁移。好的捕获22,微软。

有什么猜测这里发生了什么?

我想知道上面列出的迁移是否正在使用EntityFramework这一事实是个问题。似乎也许因为它不再是最新的迁移,当EF到达它时尝试创建一个SomeDbContext对象,它检查数据库(因为我们正在运行迁移,它还没有完全更新)对我当前的代码模型,然后抛出“上下文已经改变”错误。

2 个答案:

答案 0 :(得分:1)

这可能与您在迁移中使用EF有关。除非您设置了空数据库初始化程序,否则我不确定您是如何实际管理此内容的。

如果您需要更新迁移中的数据,请使用Sql功能,例如

Sql("UPDATE SomeTable SET SomeField = 'Blah'");

您应该注意,Up()方法在进行迁移时实际上并未运行,它只是用于设置迁移,然后稍后运行。因此,尽管您可能认为您已经在迁移中完成了某些事情,但您实际上还没有使用EF。

如果您无法重构计算代码以便可以用SQL编写,那么您需要使用除迁移之外的某种机制来运行此更改。一种可能性是在配置中使用Seed方法,但您需要知道这不会跟踪更改是否已运行。例如......

internal sealed class Configuration : DbMigrationsConfiguration<MyContext>
{
    public Configuration()
    {
        AutomaticMigrationsEnabled = false;
    }

    protected override void Seed(MyContext context)
    {
        // Code here runs any time ANY migration is performed...
    }
}

答案 1 :(得分:0)

我尝试用常规ADO.NET代码替换EntityFramework代码,它似乎工作。这是它的样子:

public override void Up()
{
    Dictionary<long, string> idToNewVal = new Dictionary<long, string>();

    using (SqlConnection conn = new SqlConnection("..."))
    {
        conn.Open();

        using (SqlCommand cmd = new SqlCommand("SELECT SomeID, SomeField FROM SomeTable", conn))
        {
            SqlDataReader reader = cmd.ExecuteReader();

            //loop through all fields, calculating the new value and storing it with the row ID
            while (reader.Read())
            {
                long id = Convert.ToInt64(reader["SomeID"]);
                string initialValue = Convert.ToString(reader["SomeField"]);
                idToNewVal[id] = DoSomeCalculation(initialValue);
            }
        }
    }

    //update each row with the new value
    foreach (long id in idToNewVal.Keys)
    {
        string newVal = idToNewVal[id];
        Sql(string.Format("UPDATE SomeTable SET SomeField = '{0}' WHERE SomeID = {1}", newVal, id));
    }
}