如何使用实体框架 CodeFirst 为我的数据库提供种子?

发布于 2024-11-15 01:54:36 字数 2506 浏览 5 评论 0原文

数据库已成功创建(表也是如此),但未设定种子。我花了几个小时并阅读了大量文章,但一直没能得到它。有什么建议吗?

附带说明一下,是否可以在客户端中不引用我的 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>

解决方案

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

The database is created successfully (as are the tables) but is not seeded. I have spent several hours and read tons of articles but have not been able to get it. Any suggestions?

On a side note, is it possible to call the initializer without having a reference to my DatabaseContext in the client?

I have included all the relevant code I could think of. If anything else would be helpful, please let me know.

Things I've Tried:

  1. I deleted my connection string (since it defaults to sqlexpress anyways, just the name changed)
  2. I changed DropCreateDatabaseIfModelChanges to DropCreateDatabaseAlways, still the same.

Edit: The really weird thing is it worked once, but I have no idea how or why it broke again. I am assuming connection strings, but who knows.

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

Client web.config

<connectionStrings>
  <add name="DatabaseContext" connectionString="data source=.\SQLEXPRESS;Database=Database;Integrated Security=SSPI;" providerName="System.Data.SqlClient" />
</connectionStrings>

SOLUTION

For the sake of documentation, I am sharing my solution here. Navigating all the comments would be a pain anyways. In the end I had DatabaseInitializer and DatabaseContext in separate classes. I don't really understand while these tiny changes fixed it, but here it is.

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(12

呆橘 2024-11-22 01:54:36

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

我已经使用过这种模式几次,它对我来说效果很好。

This is what my DbContext classes all look like and they seed just fine:

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
    }
}

I have used this pattern a few times and it has worked out very well for me.

梦回梦里 2024-11-22 01:54:36

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

My Seed method was not invoked even with proper call to Database.SetInitializer in Application_Start... The reason for it was really simple: initializer may not be invoked at all if you don't yet have any code that actually uses database context.

过期以后 2024-11-22 01:54:36

这是我悲伤的小故事。

首先,经验教训:

  1. 在使用上下文之前,不会调用种子方法。
  2. Global.asax.cs 在第一次运行时不会命中断点,因为它在附加调试器之前运行。命中断点
    Global.asax.cs,您可以在 Web.config 中添加一些空格,
    点击一个页面;那么它就会受到打击。
  3. 如果有VS连接
    对于数据库,播种不会发生。该应用程序将抛出错误。

因此,为了避免悲伤:

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

现在,悲伤的是:

  1. 我的 Global.asax.cs 文件中有自定义初始化器类。我的初始化器种子方法有一个断点;我启动了该应用程序,但该方法从未被命中。 :(
  2. 我在 Application_Start 中的 Database.SetInitializer 调用中指定了一个断点。那从未被击中。:(
  3. 我意识到我没有更改数据库架构,所以我将 DropCreateDatabaseIfModelChanges 更改为 DropCreateDatabaseAlways。仍然没有任何结果。:(
  4. 我终于去了到使用上下文的页面,并且它有效:/

This is my sad little tale.

First, lessons learned:

  1. The seed method won't be called until the context is used.
  2. The Global.asax.cs won't hit a breakpoint on first run bc it runs before the debugger is attached. To hit a breakpoint on
    Global.asax.cs, you have can add some white space to Web.config and
    hit a page; then it will get hit.
  3. If there are VS connections
    to the db, the seeding won't happen. The app will throw an error.

So, to avoid the sadness:

  • Disconnect your VS connection.
  • Switch the base class DropCreateDatabaseAlways for one go.
  • Hit a page that uses the context.

Now, the sadness:

  1. I had my custom Initializer class in my Global.asax.cs file. I had a break point on my Initializer Seed method; I started the application and the method never got hit. :(
  2. I point a break point in my Database.SetInitializer call in Application_Start. That never got hit. :(
  3. I realized that I had no db schema changes, so then I changed DropCreateDatabaseIfModelChanges to DropCreateDatabaseAlways. Still, nothing. :(
  4. I finally went to a page that uses the context, and it worked. :/
三生一梦 2024-11-22 01:54:36

您可以调用 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" }
        );
    }
}

You can call update-database to manually run the seed method inside the Configuration class. This requires enable-migrations to be on as well.

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" }
        );
    }
}
笑饮青盏花 2024-11-22 01:54:36

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

The following change in the Global.asax file worked for me:

Old Code:

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

New Code:

    protected void Application_Start()
    {
        Database.SetInitializer<mycontextclassname>(new DropCreateDatabaseAlways<mycontextclassname>()); 
        Database.SetInitializer(new Initializer()); 
        ...
    }
往日 2024-11-22 01:54:36

我也很难调用 Seed() 。我确实很感谢上面所有有用的建议,并且使用 DropCreateDatabaseAlways 获得了一些运气……但并非总是如此!

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

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

    }

足以触发 Seed() 被调用。如果您已经尝试了上述答案的所有方法但仍然没有成功,请尝试一下。祝你好运,这确实是一次耗时的经历。

I too have had difficulty getting Seed() to be invoked. And I do appreciate all the helpful suggestions above and have had some luck using DropCreateDatabaseAlways ... but not ALWAYS!!

Most recently, I added the following line of code in the the constructor of my Repository to good effect:

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

    }

It was sufficient to trigger the Seed() getting invoked. If you've tried everything above this answer and still no luck, give it a try. Good luck this was really a time consuming experience.

违心° 2024-11-22 01:54:36

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

编辑

这是我的 DataContext

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

The seed event in your example will only be fired once as your using DropCreateDatabaseIfModelChanges you can change this to DropCreateDatabaseAlways i think and it should fire the seed event every time.

Edit

This is my DataContext

public WebContext()
{   
    DbDatabase.SetInitializer(new DropCreateDatabaseIfModelChanges<WebContext>());
}
溺深海 2024-11-22 01:54:36

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

如果您决定稍后通过实施基于 DropCreateDatabaseIfModelChanges 的策略来执行此操作,但不修改模型,那么自数据库生成和您的数据库生成以来,您的 Seed 方法将不会被调用。仅当您下次更改模型时才会应用策略。

如果这种情况发生在您身上,只需尝试稍微修改您的模型来测试这个假设,我敢打赌,您的数据库将会被填充;)

我还没有解决方案,除了使用始终生成数据库的策略,但我真的不喜欢将初始化策略放入 DbContext 中,因为此类将在生产环境中使用,尽管初始化策略似乎主要用于流畅的开发环境。

This just happened to me while I was discovering Code First Features. This situation often happens when you have first used Code First to generate your database without any initialization strategy.

If you decide to do so later on by implementing a DropCreateDatabaseIfModelChanges based strategy, but without modifying you model, then your Seed method won't be called since the database generation and your strategy will only be applied next time you change your model.

If this happens to you, just try to modify your model a bit to test this hypothesis and I bet, your database is going to be populated ;)

I don't have the solution yet, except using a strategy that always generate the database, but I'm really not confortable with the fact of putting the initialization strategy in your DbContext since this class is goind to be used in you production environement, althought the initialization strategy seems to be mostly used for fluent developement environnement.

失退 2024-11-22 01:54:36

我刚刚遇到这个问题。我已从 Web.config 文件中删除了“connectionstrings”部分,并且当前应用程序开始运行 - 没有连接字符串部分!我添加回该部分,并且数据库不再重新播种。这不是一个正确的解决方案,但我只是在此处添加一个可能解决问题的数据点。

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

I've just come across this problem. I've deleted the "connectionstrings" section from the Web.config file, and currently the app started running - without the connectionstrings section! I add the section back, and the database is not seeding again. It's not a proper solution, but I'm just adding a data point here to what can potentially solve the problem.

Fortunately it's just a small "throwaway" app I'll discard soon anyway ...

没︽人懂的悲伤 2024-11-22 01:54:36

仔细确保您没有多次声明上下文变量。如果在播种后再次声明,种子将被覆盖。

Meticulously ensure that you didn't declare your context variable more than once. If you declare it again after seeding, the seed will be overwritten.

三岁铭 2024-11-22 01:54:36

我遇到了同样的问题,在更改 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>

I was having same problem and after change in both Global.asax file and Intializer file it worked. I hope it will work for those who are still having problem for data seeding.

New Code in Global.asax:

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

code for Intializer file:

public class Initializer : System.Data.Entity.DropCreateDatabaseAlways<Context>
淡淡の花香 2024-11-22 01:54:36

已更新,请注意此答案不正确!我的数据库没有获得种子的原因仍然是一个谜(但这并不是缺少默认的基本构造函数调用,正如@JaredReisinger 所指出的)

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

我的数据库创建得很好,但没有播种,即使我删除了数据库并使用 DropDatabaseInitialiser 重新开始。

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

public MyApp_Context()
{
    // some code
}

,而上面的示例对于我的设置如下所示是的

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

,我没有调用基础对象的构造函数!我没想到除了播种之外的所有东西都能在这种情况下工作,但这似乎是(可重复的)情况。

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

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

Updated to note that this answer is incorrect! The reason for my DB not getting seeded remains a mystery (but it wasn't the lack of a default base constructor call, as noted by @JaredReisinger)

I appreciate this question is a little old but I ended up here so someone else might. Here's my tuppence worth:

My DB was getting created fine but not seeded, even if I deleted the database and started again using DropDatabaseInitialiser.

After reading the code above I noticed that my context constructor was this

public MyApp_Context()
{
    // some code
}

whereas the example above would be as follows for my setup

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

Yup, I wasn't calling the base object's constructor! I wouldn't have expected everything except seeding to work in this instance but that appears to be the (repeatable) case.

NB, I don't actually need to supply the context name in the base constructor call; I only wrote it that way initially because I was copying the format of the solution above. So my code is now this, and seeding works on initial database creation.

public MyApp_Context() : base()
{
    // some code
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文