【问题标题】:How can I get my database to seed using Entity Framework CodeFirst?如何使用 Entity Framework Code First 让我的数据库播种?
【发布时间】:2011-09-12 19:55:21
【问题描述】:

数据库已成功创建(与表一样),但未播种。我花了几个小时阅读了大量的文章,但一直没能得到它。有什么建议吗?

附带说明一下,是否可以调用初始化程序而无需在客户端中引用我的 DatabaseContext?

我已经包含了我能想到的所有相关代码。如果还有什么有用的,请告诉我。

我尝试过的事情:

  1. 我删除了我的连接字符串(因为无论如何它默认为 sqlexpress,只是名称已更改)
  2. 我将 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 类。

标签: entity-framework asp.net-mvc-3 frameworks entity code-first


【解决方案1】:

您的示例中的种子事件只会被触发一次,因为您使用 DropCreateDatabaseIfModelChanges 您可以将其更改为 DropCreateDatabaseAlways 我认为它应该每次都触发种子事件。

编辑

这是我的数据上下文

public WebContext()
{   
    DbDatabase.SetInitializer(new DropCreateDatabaseIfModelChanges<WebContext>());
}

【讨论】:

  • 我尝试过切换。没有运气。仍然创建了数据库和所有表,但没有种子。
  • 我调用 Database.SetInitializer(new DatabaseInitializer());在适用于我的 DatabaseContext 的构造函数中
  • 我不能在 DatabaseContext 中引用 DatabaseInitializer,因为那将是一个循环引用。此外,它不需要进入 DatabaseContext 构造函数,因为它应该由 App_Start 中的 DatabaseInitializer 构造函数调用(据我的理解)。
【解决方案2】:

这就是我的 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】:

          这是我悲伤的小故事。

          首先,经验教训:

          1. 在使用上下文之前不会调用种子方法。
          2. Global.asax.cs 在第一次运行时不会遇到断点,因为它在附加调试器之前运行。打断点 Global.asax.cs,您可以在 Web.config 和 点击一页;那么它就会被击中。
          3. 如果有 VS 连接 到分贝,播种不会发生。应用会抛出错误。

          所以,为了避免悲伤:

          • 断开 VS 连接。
          • 一次性切换基类 DropCreateDatabaseAlways。
          • 点击使用上下文的页面。

          现在,悲伤:

          1. 我的 Global.asax.cs 文件中有我的自定义 Initializer 类。我的 Initializer Seed 方法有一个断点;我启动了应用程序,但该方法从未受到影响。 :(
          2. 我在 Application_Start 中的 Database.SetInitializer 调用中设置了一个断点。那从来没有受到打击。 :(
          3. 我意识到我没有更改数据库架构,因此我将 DropCreateDatabaseIfModelChanges 更改为 DropCreateDatabaseAlways。依然没有。 :(
          4. 我终于找到了一个使用上下文的页面,并且它有效。 :/

          【讨论】:

          • 这很有效,感谢您提供这些有用的信息。我关闭了数据库连接,然后将基类切换为 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
              }
              

              【讨论】:

              • 只要您不直接调用它的特定变体,就会自动调用基类的默认构造函数。有关详细信息,请参阅stackoverflow.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>
                

                【讨论】:

                  猜你喜欢
                  • 2013-06-14
                  • 1970-01-01
                  • 2011-07-14
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2017-10-04
                  • 2014-03-07
                  相关资源
                  最近更新 更多