如何使用Entity Framework Code First让我的数据库播种?

时间:2011-06-10 21:38:34

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

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

另外,是否可以在客户端没有引用我的DatabaseContext的情况下调用初始化程序?

我已经包含了我能想到的所有相关代码。如果有任何其他方面的帮助,请告诉我。

我尝试过的事情:

  1. 我删除了我的连接字符串(因为它默认为sqlexpress,只是名称已更改)
  2. 我将DropCreateDatabaseIfModelChanges更改为DropCreateDatabaseAlways,仍然相同。
  3. 编辑:非常奇怪的是它曾经工作过一次,但我不知道它是如何或为什么再次爆发。我假设连接字符串,但谁知道。

    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>
    

    为了记录,我在这里分享我的解决方案。无论如何,浏览所有评论都会很痛苦。最后,我将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);
    }
    

12 个答案:

答案 0 :(得分:37)

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

我已经使用过这种模式了几次,它对我来说非常好。

答案 1 :(得分:10)

即使在Seed中正确调用Database.SetInitializer,我的Application_Start方法也未被调用...原因很简单:如果您不打算使用初始化程序,则可能根本无法调用还有任何实际使用数据库上下文的代码。

答案 2 :(得分:9)

这是我悲伤的小故事。

首先,经验教训:

  1. 在使用上下文之前,不会调用种子方法。
  2. Global.asax.cs在连接调试器之前运行的第一次运行时不会遇到断点。打一个断点 Global.asax.cs,你可以为Web.config和。添加一些空格 打了一页;然后就会受到打击。
  3. 如果有VS连接 到数据库,播种不会发生。该应用程序将抛出错误。
  4. 所以,为了避免悲伤:

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

    现在,悲伤:

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

答案 3 :(得分:3)

您可以调用update-databaseConfiguration类中手动运行种子方法。这也需要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" }
        );
    }
}

答案 4 :(得分:2)

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()); 
        ...
    }

答案 5 :(得分:1)

我也很难调用Seed()。我非常感谢上面提到的所有有用的建议,并且使用DropCreateDatabaseAlways运气好了......但不是总是!!

最近,我在我的存储库的构造函数中添加了以下代码行,效果很好:

    public CatalogRepository()
    {
        _formCatalog.FormDescriptors.GetType();

    }

触发Seed()被调用就足够了。如果你已经尝试了这个答案之上的所有内容并且仍然没有运气,请试一试。祝你好运,这真是一段耗时的经历。

答案 6 :(得分:0)

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

修改

这是我的DataContext

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

答案 7 :(得分:0)

当我发现Code First Features时,这恰好发生在我身上。当您第一次使用Code First生成数据库而没有任何初始化策略时,通常会发生这种情况。

如果您稍后决定实施基于DropCreateDatabaseIfModelChanges的策略,但未修改模型,则不会调用Seed方法,因为数据库生成和您的策略只会下次更换模型时应用。

如果您遇到这种情况,只需尝试修改您的模型以测试此假设,我敢打赌,您的数据库将会被填充;)

我还没有解决方案,除了使用始终生成数据库的策略,但我真的不能将初始化策略放在DbContext中,因为这个类是goind用于你生产环境,虽然初始化策略似乎主要用于流畅的开发环境。

答案 8 :(得分:0)

我刚遇到这个问题。我已从Web.config文件中删除了“connectionstrings”部分,并且当前应用程序已开始运行 - 没有connectionstrings部分!我添加了部分,数据库不再播种。这不是一个合适的解决方案,但我只是在这里添加一个可以解决问题的数据点。

幸运的是,它只是一个小的“一次性”应用程序,我很快就会丢弃......

答案 9 :(得分:0)

更新以注意此答案不正确!我的数据库没有被播种的原因仍然是一个谜(但不是缺少默认的基础构造函数调用,如@JaredReisinger所述)

我很欣赏这个问题有点老了,但我最终在这里,所以其他人可能。这是我值得的值得:

即使我删除了数据库并使用DropDatabaseInitialiser再次启动,我的数据库也被创建得很好但没有播种。

在阅读上面的代码后,我注意到我的上下文构造函数是这个

public MyApp_Context()
{
    // some code
}

而上面的例子对我的设置如下

public MyApp_Context() : base("name=MyApp_Context")
{
    // some code
}

是的,我没有调用基础对象的构造函数!我不会期望除了播种之外的所有内容都可以在这种情况下工作,但这似乎是(可重复的)案例。

注意,我实际上并不需要在基础构造函数调用中提供上下文名称;我最初只是这样写的,因为我正在复制上面解决方案的格式。所以我的代码现在是这样的,种子在初始数据库创建时起作用。

public MyApp_Context() : base()
{
    // some code
}

答案 10 :(得分:0)

谨慎地确保您不会多次声明您的上下文变量。如果在播种后再次声明它,种子将被覆盖。

答案 11 :(得分:0)

我遇到了同样的问题,并且在Global.asax文件和Intializer文件发生更改后都有效。我希望它对那些仍然存在数据播种问题的人有用。

Global.asax中的新代码:

    protected void Application_Start()
    {
        Database.SetInitializer<mycontextclassname>(new DropCreateDatabaseAlways<mycontextclassname>()); 
        Database.SetInitializer(new Initializer()); 
        ...
    }

Intializer文件的代码:

public class Initializer : System.Data.Entity.DropCreateDatabaseAlways<Context>