实体框架5迁移:设置数据库的初始迁移和单个种子



我有一个MVC4应用程序,我最近升级到了Entity Framework 5,我正试图将我们的数据库从每次运行的删除和创建的开发风格转移到使用迁移。

以下是我在应用程序启动功能中所做的操作。

protected void Application_Start()
{
Database.SetInitializer(
new MigrateDatabaseToLatestVersion< MyContext, Configuration >() );
...
}

我在我的存储库项目上运行了Enable-Migrations命令,我认为这将创建一个初始迁移文件,但它创建的唯一文件是Configuration

当我删除数据库时,它会首先通过代码按预期创建它,并从配置文件中种子数据库。在配置文件中,我将所有Add()功能更改为AddOrUpdate()

然而,每次网站启动时,它都会在我的Configuration文件中运行种子函数,并一次又一次地复制所有种子数据。

我想象它会像我读到的博客建议的那样创建一个initial migration文件,我可以把种子数据放在那里,但它没有

有人能解释一下我应该如何在代码中设置DB,使其只种子一次吗?


链接:我关注的迁移博客文章


虽然这对于使用EF migrate.exe来说非常有趣,但我后来改为使用roundhouse来运行迁移。我仍然使用EF来构建基于模型的迁移,但我写了一个控制台应用程序来将迁移写入SQL文件。然后,我使用roundhouse通过我的rake构建脚本自己执行迁移。这涉及到更多的过程,但它比在应用程序启动时使用EF动态执行迁移要稳定得多。

事实证明这是一篇很受欢迎的帖子,所以我根据其他人的反馈进行了更新。需要知道的主要一点是,Configuration类中的Seed方法在每次应用程序启动时都会运行,这不是template方法中的注释所暗示的。看看微软的某个人对这篇文章的回答——感谢Jason Learmouth的发现。

如果您像我一样,只想在有任何挂起的迁移时运行数据库更新,那么您需要做更多的工作。您可以通过调用migrator来发现是否存在挂起的迁移。GetPendingMigrations(),但必须在ctor中执行此操作,因为在调用Seed方法之前,挂起的迁移列表已被清除。实现这一点的代码位于Migrations.Configuration类中,如下所示:

internal sealed class Configuration : DbMigrationsConfiguration<YourDbContext>
{ 
private readonly bool _pendingMigrations;
public Configuration()
{
// If you want automatic migrations the uncomment the line below.
//AutomaticMigrationsEnabled = true;
var migrator = new DbMigrator(this);
_pendingMigrations = migrator.GetPendingMigrations().Any();
}
protected override void Seed(MyDbContext context)
{
//Microsoft comment says "This method will be called after migrating to the latest version."
//However my testing shows that it is called every time the software starts
//Exit if there aren't any pending migrations
if (!_pendingMigrations) return;
//else run your code to seed the database, e.g.
context.Foos.AddOrUpdate( new Foo { bar = true});
}
}

我应该指出,有些人建议将种子代码放在实际的"向上"迁移代码中。这是有效的,但意味着你需要记住在每次新的迁移中放入种子代码,这很难记住,所以我不会这么做。然而,若你们的种子随着每次迁移而变化,那个么这可能是一个很好的方法。

您可以手动添加迁移并用您想要的任何种子代码填充它吗?在包管理器控制台中运行:

Add-Migration [Name]

然后,您可以编辑迁移文件夹中为您创建的文件。

在我的项目中,我实际上像Richard一样在上下文配置的Seed方法中进行种子设定。我真的没有偏好。但是迁移应该更高效,因为在应用程序启动时,应用程序不需要检查数据库中是否存在行。只需要检查迁移是否已经运行,这应该会更快。

internal sealed class Configuration : DbMigrationsConfiguration<MyContext>
{
public Configuration()
{
// If you want automatic migrations as well uncomment below.
// You can use both manual and automatic at the same time, but I don't recommend it.
//AutomaticMigrationsEnabled = true;
//AutomaticMigrationDataLossAllowed = true;
}
protected override void Seed(MyContext context)
{
//  This method will be called after migrating to the latest version.
//  You can use the DbSet<T>.AddOrUpdate() helper extension method 
//  to avoid creating duplicate seed data.
context.FontFamilies.AddOrUpdate(
f => f.Id,
new FontFamily { Id = 1, PcName = "Arial" },
new FontFamily { Id = 2, PcName = "Times New Roman" },
});

我在Global.asax:中使用这个

public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
// Any migrations that haven't been applied before will
// automatically be applied on Application Pool restart
Database.SetInitializer<MyContext>(
new MigrateDatabaseToLatestVersion<MyContext,
MyApp.Migrations.Configuration>()
);
}
}

这也是我过去一直想知道的事情。我的数据库中有一些表在我的Seed事件中填充,现在我只检查Seed方法中是否有一个表为空。如果存在行,则Seed方法不会运行。并非万无一失,但确实奏效。

这个SO问题的答案解释了为什么每次运行应用程序时都会运行Seed。

我使用Jon-Smiths方法,但我在#if块中检查了挂起的迁移语句,如下所示:

#if (!DEBUG)
if (!_pendingMigrations) return;
#endif

这样,当我调试时,Seed方法总是运行来重新填充我的种子数据——当我在测试等过程中进行删除时很有用,但在发布时我不会得到性能命中率。

最新更新