asp.net-mvc 实体框架 5 迁移:设置数据库的初始迁移和单一种子
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/13510341/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Entity Framework 5 Migrations: Setting up an initial migration and single seed of the database
提问by Neil
I have an MVC4 app which I've recently upgraded to Entity Framework 5 and I am trying to move our database over to using migrations from the development style of dropping and creating each run.
我有一个 MVC4 应用程序,我最近已将其升级到 Entity Framework 5,我正在尝试将我们的数据库从删除和创建每次运行的开发风格迁移到使用迁移。
Here's what I've done in my app start function.
这是我在我的应用程序启动功能中所做的。
protected void Application_Start()
{
Database.SetInitializer(
new MigrateDatabaseToLatestVersion< MyContext, Configuration >() );
...
}
I ran the Enable-Migrationscommand on my repositories project and I thought that this would create an initial migration file however the only file it created was Configuration
我Enable-Migrations在我的存储库项目上运行了命令,我认为这会创建一个初始迁移文件,但是它创建的唯一文件是Configuration
When I delete the database it creates it as expected via code first and seeds the database from the Configuration file. In the configuration file I changed all the Add()functions to AddOrUpdate()
当我删除数据库时,它首先通过代码按预期创建它,然后从配置文件中为数据库设置种子。在配置文件中,我将所有Add()功能更改为AddOrUpdate()
However it runs the seed function in my Configurationfile each time the website starts and duplicates all the seed data again and again.
但是,Configuration每次网站启动时它都会在我的文件中运行种子功能,并一次又一次地复制所有种子数据。
I imagined that it would create an initial migrationfile as the blog I read suggested that it would and I could put the seed data in there but it didn't
我想象它会创建一个initial migration文件,因为我读过的博客建议它会并且我可以将种子数据放在那里,但它没有
Can anyone explain how I should be setting up DB in code so that it only seeds once?
谁能解释我应该如何在代码中设置数据库,以便它只播种一次?
LINK: The migrations blog post I followed
While this is quite interesting for using the EF migrate.exe I've since switched to using roundhousefor running migrations. I still use EF to scaffold my migrations based on the models but I wrote a little console app to write the migrations out to SQL files. I then use roundhouse to perform the migrations themselves through my rake build scripts. There's a little more process involved but it's much more stable than using EF to perform the migrations on the fly when the application starts up.
虽然这对于使用 EF migrate.exe 非常有趣,但我已经转而使用roundhouse来运行迁移。我仍然使用 EF 来搭建基于模型的迁移,但我编写了一个小控制台应用程序来将迁移写入 SQL 文件。然后我使用 roundhouse 通过我的 rake 构建脚本自行执行迁移。涉及的过程要多一些,但它比在应用程序启动时使用 EF 即时执行迁移要稳定得多。
回答by Jon P Smith
This has proved to be a popular post so I have updated it in light of feedback from others. The main thing to know is that the Seed method in the Configuration class is run EVERY time the application starts, which isn't what the comment in the template method implies. See the answer from someone at Microsoft to this postabout why that is - thanks to Jason Learmouth for finding that.
事实证明,这是一篇受欢迎的帖子,因此我根据其他人的反馈对其进行了更新。要知道的主要事情是每次应用程序启动时都会运行 Configuration 类中的 Seed 方法,这不是模板方法中的注释所暗示的。请参阅 Microsoft 某人对这篇文章的回答,了解为什么会这样 - 感谢 Jason Learmouth 找到了这一点。
If you, like me, only want to run the database updates if there are any pending migrations then you need to do a bit more work. You can find that out if there are pending migrations by calling migrator.GetPendingMigrations(), but you have to do that in the ctor as the list of pending migrations is cleared before Seed method is called. The code to implement this, which goes in the Migrations.Configuration class is as follows:
如果您和我一样,只想在有任何挂起的迁移时运行数据库更新,那么您需要做更多的工作。您可以通过调用 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});
}
}
I should point out that some people have suggested putting the seed code in the actual 'up' migration code. This works, but means you need to remember to put the seed code in each new migration and its pretty hard remember so I wouldn't do that. However if your seed changes with each migration then that might be the a good way to go.
我应该指出,有些人建议将种子代码放在实际的“向上”迁移代码中。这有效,但意味着您需要记住将种子代码放在每个新的迁移中,而且很难记住,所以我不会这样做。但是,如果您的种子随着每次迁移而变化,那么这可能是一个好方法。
回答by oldwizard
You could add a migration manually and fill it with whatever seeding code you want? In package manager console run:
您可以手动添加迁移并用您想要的任何种子代码填充它吗?在包管理器控制台中运行:
Add-Migration [Name]
You can then edit that file which is created for you in your migrations folder.
然后,您可以编辑在迁移文件夹中为您创建的文件。
In my project i actually do seeding like Richard though in the Seed method of the context configuration. I really have no preference. But migrations should be more efficient in that the application doesn't need to check if the rows exist in the database when the application starts. There is just the need to check if the migration has been run, which should be faster.
在我的项目中,我实际上像 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" },
});
I'm using this in Global.asax:
我在 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>()
);
}
}
回答by Richard
This is something I've wondered about in the past too. I have certain tables in my database which get populated in my Seed event, and now I just check to see if one of them is empty within the Seed method. If there are rows, the Seed method doesn't run. Not infallible, but does the trick.
这也是我过去一直想知道的。我的数据库中有某些表会填充到我的 Seed 事件中,现在我只是检查其中一个表是否在 Seed 方法中为空。如果有行,则不会运行 Seed 方法。并非万无一失,但确实有效。
回答by Jason Learmouth
The answer to this SO questionexplains why Seed runs every time the app runs.
这个 SO 问题的答案解释了为什么每次应用程序运行时种子都会运行。
I use Jon Smiths method, but I have put the check for pending migrations statement in an #if block like this:
我使用 Jon Smiths 方法,但我已将挂起迁移语句的检查放在 #if 块中,如下所示:
#if (!DEBUG)
if (!_pendingMigrations) return;
#endif
That way when I'm debugging the Seed method always runs to repopulate my seed data - useful when I do deletes during testing, etc. but I don't get the perf hit when in release.
这样,当我调试 Seed 方法时,它总是运行以重新填充我的种子数据 - 当我在测试期间进行删除等时很有用,但在发布时我没有得到性能命中。

