手动运行Entity Framework迁移Seed()方法,包括在Down()迁移之后

时间:2016-03-05 19:51:22

标签: c# entity-framework

是否有一种从包管理器控制台手动运行Entity Framework迁移Seed()方法的简单方法,包括在Down()迁移(Update-Database -TargetMigration foo)之后? “Run Code First Migration Seed Method without a migration”的答案解决了如何手动运行Seed()方法,即调用Update-Database,但是当数据库处于较旧的迁移且不应更新时,这不起作用。在“How to run Seed() method of Configuration class of migrations”中提出了同样的问题,但它被问为多部分问题的一部分,而这一部分仍然没有答案(尽管整个问题现已标记为已回答)。

我问,因为我有一些需要在应用迁移后运行的清理代码。从Seed()调用它可以正常进行Up()迁移。不过,我不知道如何轻松调用它进行Down()迁移。我想要一个简单的,一个或两个衬里,可以从包管理器。我知道在为所有必要的DLL调用[Reflection.Assembly] :: LoadFile()之后我可以调用c#方法,但是有足够的依赖关系,这会很麻烦且容易出错。

我知道Seed()不是Down()迁移清理代码的理想位置(根据DrewJordan的回答添加一些上下文),但遗憾的是,由于多种原因使用Down()本身是不可行的。从实际的角度来看,它是不可行的,因为清理必须转换几千兆字节的数据,这导致SQL Server Express在我尝试Down()中的简单副本时崩溃,可能是因为产生的事务大小非常大。其次,从一个假设的角度来看,我不相信有一种方法可以将数据转换为Down()所需的范围,因为当前的SQL行无法在c#中作为事务的一部分读取,并且数据的转换也是如此。需要在c#中进行。有关该限制的详细信息,请参阅我的其他问题:“Transform data using c# during Entity Framework migration”。需要对设计进行一些折衷才能使清理工作,并且我使用Seed()作为妥协。清理代码本身不需要从Seed()运行,但我不知道在不改变当前迁移的情况下可以从包管理器调用什么。

还有另一种情况是,在不更改当前迁移的情况下自行调用Seed()或其他清理代码会很有用。考虑Seed()/ cleanup方法中存在错误的情况。您修复了该错误,并希望在不更改当前迁移的情况下重新运行该错误。将清理逻辑放在Down()中并不能解决问题,因为当数据库已经在迁移时,不会调用Down()。

2 个答案:

答案 0 :(得分:1)

我意识到你问过从PM控制台运行它:AFAIK它是不可能的。这个用例不是Seed的用途:如果您要在Down方法中进行更改,可以编写SQL脚本来运行,或者在{{1中创建上下文并做任何事情。

这是一个坏主意,因为Down指望与最新的迁移保持同步。例如,它允许您编写在上下文的先前版本上可能成功的语句,例如将列添加到模型但尚未应用于数据库时。我没有试过这个,但它至少会抛出异常,并且可能无法编写任何更改。

如果您真的,认为这是一个好主意,您可以在配置中添加方法:

Seed

从Down打电话:

public void CallSeed()
{
    using (var c = new Context()) // create your context
    {
        Seed(c);
    }
}

答案 1 :(得分:0)

我找到了看起来会起作用的基础。这是一个黑客,但我会在这里发布,因为我知道其他人想要类似的东西,从我链接的其他堆栈溢出问题来判断。

这个想法是捎带另一个可以从包管理器运行的迁移命令,它不会改变数据库本身 - 我将使用Get-Migrations。这将允许package-manager命令完成定位正确配置,加载正确的程序集等的繁重工作。我将通过从我的DbMigrationsConfiguration子类的构造函数调用我的清理代码来搭载该命令。我只想故意运行清理代码,而不是每次构造配置时,所以我还会在实际运行清理代码之前检查一个sentinel环境变量。后来,我打算将清理代码从Seed()中移出,以便将它与实际种子分开,但由于其他人在过去询问过手动运行Seed(),我将在此处使用它作为示例。

我更改了我的DbMigrationsConfiguration子类,如下所示:

internal sealed class Configuration : DbMigrationsConfiguration<TimsDB>
{

    public Configuration()
    {
        if ("true".Equals(Environment.GetEnvironmentVariable("RUN_SEED")))
            using (TimsDB db = new TimsDB())
            {
                Database.SetInitializer<TimsDB>(null);
                Seed(db);
            }
        }
    }

    ...

}

然后可以使用它从包管理器手动调用Seed()方法:

PM> $Env:RUN_SEED = "true"
PM> Get-Migrations
PM> $Env:RUN_SEED = "false"