如何使用 Entity Framework Code First 让我的数据库播种?
Posted
技术标签:
【中文标题】如何使用 Entity Framework Code First 让我的数据库播种?【英文标题】:How can I get my database to seed using Entity Framework CodeFirst? 【发布时间】:2011-09-12 19:55:21 【问题描述】:数据库已成功创建(与表一样),但未播种。我花了几个小时阅读了大量的文章,但一直没能得到它。有什么建议吗?
附带说明一下,是否可以调用初始化程序而无需在客户端中引用我的 DatabaseContext?
我已经包含了我能想到的所有相关代码。如果还有什么有用的,请告诉我。
我尝试过的事情:
-
我删除了我的连接字符串(因为无论如何它默认为 sqlexpress,只是名称已更改)
我将 DropCreateDatabaseIfModelChanges 更改为 DropCreateDatabaseAlways,还是一样。
编辑:真正奇怪的是它曾经工作过,但我不知道它是如何或为什么再次坏掉的。我假设连接字符串,但谁知道呢。
DatabaseInitializer.cs
public class DatabaseInitializer : DropCreateDatabaseIfModelChanges<DatabaseContext>
protected override void Seed(DatabaseContext context)
// Seeding data here
context.SaveChanges();
DatabaseContext.cs
public class DatabaseContext : DbContext
protected override void OnModelCreating(DbModelBuilder mb)
// Random mapping code
public DbSet<Entity1> Entities1 get; set;
public DbSet<Entity2> Entities2 get; set;
Global.asax.cs - Application_Start()
protected void Application_Start()
Database.SetInitializer<DatabaseContext>(new DatabaseInitializer());
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
客户端 web.config
<connectionStrings>
<add name="DatabaseContext" connectionString="data source=.\SQLEXPRESS;Database=Database;Integrated Security=SSPI;" providerName="System.Data.SqlClient" />
</connectionStrings>
解决方案
为了文档,我在这里分享我的解决方案。无论如何,导航所有的 cmets 都会很痛苦。最后,我在不同的类中有 DatabaseInitializer 和 DatabaseContext。虽然这些微小的变化修复了它,但我真的不明白,但就是这样。
DatabaseInitializer.cs
public class DatabaseInitializer : CreateDatabaseIfNotExists<DatabaseContext>
protected override void Seed(DatabaseContext context)
// Seed code here
DatabaseContext.cs
public class DatabaseContext : DbContext
public DatabaseContext() : base("MyDatabase")
protected override void OnModelCreating(DbModelBuilder mb)
// Code here
public DbSet<Entity> Entities get; set;
// Other DbSets
Global.asax.cs - Application_Start()
protected void Application_Start()
Database.SetInitializer(new DatabaseInitializer());
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
【问题讨论】:
您是否将种子项添加到您的数据上下文中?我知道我以前错过了。 是的,我是。感谢您的检查:)。 =D 不用担心。你能在代码中设置一个断点并确保你的 Seed 被调用吗? 没有调用 Seed 方法。 DatabaseInitializer 是。我错过了什么吗? 这真的很奇怪。尝试将 Database.SetInitializer 放入 DatabaseContext 的构造函数中。另外,尝试添加 base.Seed (context);到你的种子方法。我不知道为什么这很重要,但值得检查。编辑:我看到了您对@feanz 答案的评论,但您可以将 Database.SetInitializer 放入 datacontext 的构造函数中。我 acutlaly 将我的初始化程序类 inside 我的 datacontext 类。 【参考方案1】:您的示例中的种子事件只会被触发一次,因为您使用 DropCreateDatabaseIfModelChanges 您可以将其更改为 DropCreateDatabaseAlways 我认为它应该每次都触发种子事件。
编辑
这是我的数据上下文
public WebContext()
DbDatabase.SetInitializer(new DropCreateDatabaseIfModelChanges<WebContext>());
【讨论】:
我尝试过切换。没有运气。仍然创建了数据库和所有表,但没有种子。 我调用 Database.SetInitializer这就是我的 DbContext 类的所有外观,它们的种子很好:
public class MyDbContext : DbContext
public DbSet<MyClass> MyClasses get; set;
protected override void OnModelCreating (DbModelBuilder modelBuilder)
base.OnModelCreating (modelBuilder);
modelBuilder.Conventions.Remove<System.Data.Entity.ModelConfiguration.Conventions.PluralizingTableNameConvention> ();
// Add any configuration or mapping stuff here
public void Seed (MyDbContext Context)
#if DEBUG
// Create my debug (testing) objects here
var TestMyClass = new MyClass () ... ;
Context.MyClasses.Add (TestMyClass);
#endif
// Normal seeding goes here
Context.SaveChanges ();
public class DropCreateIfChangeInitializer : DropCreateDatabaseIfModelChanges<MyDbContext>
protected override void Seed (MyDbContext context)
context.Seed (context);
base.Seed (context);
public class CreateInitializer : CreateDatabaseIfNotExists<MyDbContext>
protected override void Seed (MyDbContext context)
context.Seed (context);
base.Seed (context);
static MyDbContext ()
#if DEBUG
Database.SetInitializer<MyDbContext> (new DropCreateIfChangeInitializer ());
#else
Database.SetInitializer<MyDbContext> (new CreateInitializer ());
#endif
我已经使用过这种模式几次,对我来说效果很好。
【讨论】:
这不是我完全实现的解决方案,我在上面的原始问题中详细说明了我的解决方案。只是为了方便未来的用户使用而发布此评论。感谢 jdangelo 的所有帮助! 这是一个很好的方法,因为它不需要对 Application_Start() 进行任何更改,因此可以重复使用【参考方案3】:这只是在我发现 Code First 功能时发生在我身上。当您首次使用 Code First 生成数据库而没有任何初始化策略时,通常会发生这种情况。
如果您决定稍后通过实施基于 DropCreateDatabaseIfModelChanges
的策略来执行此操作,但不修改您的模型,那么您的 Seed
方法将不会被调用,因为数据库生成并且您的策略只会在下次应用你改变你的模型。
如果您遇到这种情况,请尝试稍微修改您的模型以测试此假设,我敢打赌,您的数据库将被填充;)
我还没有解决方案,除了使用总是生成数据库的策略,但我真的不喜欢将初始化策略放在你的 DbContext 中,因为这个类将在你身上使用生产环境,虽然初始化策略似乎主要用于流畅的开发环境。
【讨论】:
【参考方案4】:即使在Application_Start
中正确调用Database.SetInitializer
,我的Seed
方法也没有被调用...原因很简单:如果您还没有任何代码,则可能根本不会调用初始化程序实际使用数据库上下文。
【讨论】:
【参考方案5】:Global.asax 文件中的以下更改对我有用:
旧代码:
protected void Application_Start()
Database.SetInitializer<mycontextclassname>(new DropCreateDatabaseAlways<mycontextclassname>());
...
新代码:
protected void Application_Start()
Database.SetInitializer<mycontextclassname>(new DropCreateDatabaseAlways<mycontextclassname>());
Database.SetInitializer(new Initializer());
...
【讨论】:
【参考方案6】:我刚遇到这个问题。我已经从 Web.config 文件中删除了“connectionstrings”部分,并且当前应用程序开始运行 - 没有 connectionstrings 部分!我重新添加该部分,并且数据库不再播种。这不是一个合适的解决方案,但我只是在这里添加一个数据点来解决问题。
幸运的是,它只是一个小的“一次性”应用程序,无论如何我很快就会丢弃......
【讨论】:
【参考方案7】:这是我悲伤的小故事。
首先,经验教训:
-
在使用上下文之前不会调用种子方法。
Global.asax.cs 在第一次运行时不会遇到断点,因为它在附加调试器之前运行。打断点
Global.asax.cs,您可以在 Web.config 和
点击一页;那么它就会被击中。
如果有 VS 连接
到分贝,播种不会发生。应用会抛出错误。
所以,为了避免悲伤:
断开 VS 连接。 一次性切换基类 DropCreateDatabaseAlways。 点击使用上下文的页面。现在,悲伤:
-
我的 Global.asax.cs 文件中有我的自定义 Initializer 类。我的 Initializer Seed 方法有一个断点;我启动了应用程序,但该方法从未受到影响。 :(
我在 Application_Start 中的 Database.SetInitializer 调用中设置了一个断点。那从来没有受到打击。 :(
我意识到我没有更改数据库架构,因此我将 DropCreateDatabaseIfModelChanges 更改为 DropCreateDatabaseAlways。依然没有。 :(
我终于找到了一个使用上下文的页面,并且它有效。 :/
【讨论】:
这很有效,感谢您提供这些有用的信息。我关闭了数据库连接,然后将基类切换为 DropCreateDatabaseAlways。效果很好。 全局只运行第一次。所以关闭IISExpress。在全局设置断点并运行。因为它的 IIS 应用程序级别,它会命中它一次。【参考方案8】:我也很难让 Seed() 被调用。我非常感谢上面所有有用的建议,并且在使用 DropCreateDatabaseAlways 时遇到了一些运气......但并非总是如此!!
最近,我在我的 Repository 的构造函数中添加了以下代码行,效果很好:
public CatalogRepository()
_formCatalog.FormDescriptors.GetType();
触发 Seed() 被调用就足够了。如果您已经尝试了此答案之上的所有内容但仍然没有运气,请尝试一下。祝你好运,这真的是一次耗时的经历。
【讨论】:
【参考方案9】:您可以调用update-database
手动运行Configuration
类中的种子方法。这需要enable-migrations
也处于开启状态。
PM> update-database
Specify the '-Verbose' flag to view the SQL statements being applied to the target database.
No pending code-based migrations.
Running Seed method.
internal sealed class Configuration : DbMigrationsConfiguration<ProjectManager.Data.Database.ProjectDb>
public Configuration()
AutomaticMigrationsEnabled = false;
protected override void Seed(ProjectManager.Data.Database.ProjectDb context)
context.Status.AddOrUpdate(
new Status() Id = 1, Text = "New" ,
new Status() Id = 2, Text = "Working" ,
new Status() Id = 3, Text = "Completed" ,
new Status() Id = 4, Text = "Skipped"
);
【讨论】:
【参考方案10】:更新说明此答案不正确!我的数据库没有被播种的原因仍然是个谜(但这不是缺少默认的基本构造函数调用,正如@JaredReisinger 所指出的)
我很欣赏这个问题有点老了,但我最终来到了这里,所以其他人可能会这样做。这是我的 tuppence 价值:
即使我删除了数据库并使用 DropDatabaseInitialiser 重新启动,我的数据库也可以正常创建但没有播种。
阅读上面的代码后,我注意到我的上下文构造函数是这个
public MyApp_Context()
// some code
而上面的示例对于我的设置如下所示
public MyApp_Context() : base("name=MyApp_Context")
// some code
是的,我没有调用基础对象的构造函数!在这种情况下,除了播种之外,我没有预料到所有事情都可以工作,但这似乎是(可重复的)情况。
注意,我实际上不需要在基本构造函数调用中提供上下文名称;我最初只是这样写的,因为我正在复制上面解决方案的格式。所以我的代码现在是这样的,并且播种在初始数据库创建时起作用。
public MyApp_Context() : base()
// some code
【讨论】:
只要您不直接调用它的特定变体,就会自动调用基类的默认构造函数。有关详细信息,请参阅***.com/questions/13166019/…。 是的,我必须同意你的看法。唯一的事情是,当我三年前写这篇文章时,我似乎已经注意到省略(冗余) base() 调用与包含它会导致不同的结果。我可能会在某个时候挖掘出该代码,但最安全的做法可能是假设那里还有其他一些影响。【参考方案11】:仔细确保您没有多次声明上下文变量。如果在播种后再次声明,则种子会被覆盖。
【讨论】:
【参考方案12】:我遇到了同样的问题,在更改 Global.asax
文件和 Intializer
文件后它工作了。我希望它对那些仍然有数据播种问题的人有用。
Global.asax 中的新代码:
protected void Application_Start()
Database.SetInitializer<mycontextclassname>(new DropCreateDatabaseAlways<mycontextclassname>());
Database.SetInitializer(new Initializer());
...
初始化器文件代码:
public class Initializer : System.Data.Entity.DropCreateDatabaseAlways<Context>
【讨论】:
以上是关于如何使用 Entity Framework Code First 让我的数据库播种?的主要内容,如果未能解决你的问题,请参考以下文章
Entity Framework 学习系列 - 认识理解Entity Framework
如何使用 Entity Framework Core 模拟异步存储库
如何使用 Entity Framework 生成和自动递增 Id