问题 ASP.NET Core RC2种子数据库


我的问题是我试图用数据种子实体框架核心数据库,在我看来下面的代码显示工作。我意识到这不应该被称为 ApplicationDbContext 构造函数应该从中调用 startup 但我不知道该怎么做。

编辑:根据Ketrex提供的解决方案,我的解决方案如下:

Startup.cs:

    public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
    {
        ... 

        app.ApplicationServices.GetRequiredService<ApplicationDbContext>().Seed();
    }

种子延伸:

public static class DbContextExtensions
{
    public static void Seed(this ApplicationDbContext context)
    {
        // Perform database delete and create
        context.Database.EnsureDeleted();
        context.Database.EnsureCreated();

        // Perform seed operations
        AddCountries(context);
        AddAreas(context);
        AddGrades(context);
        AddCrags(context);
        AddClimbs(context);

        // Save changes and release resources
        context.SaveChanges();
        context.Dispose();
    }

    private static void AddCountries(ApplicationDbContext context)
    {
        context.AddRange(
            new Country { Name = "England", Code = "En" },
            new Country { Name = "France", Code = "Fr" }
            );
    }

    ...
}

我知道在实体框架的优先级列表中播种数据库是相当高的,但如果有一些关于如何实现这个微不足道的任务或者至少提供临时工作的文档会很好。如果有人可以就如何做到这一点提供一些指导,我们将不胜感激。我觉得我接近一个解决方案,但只是不能把它拼凑在一起。

谢谢你的帮助。


1848
2018-06-26 00:24


起源



答案:


假设您使用的是内置DI容器,这是一种可以实现此目的的方法。

在启动类的Configure方法中引用种子方法,并将IApplicationBuilder对象作为参数而不是DbContext传递,如下所示:

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
    //...
    // Put this at the end of your configure method
    DbContextSeedData.Seed(app);
}

接下来,修改种子方法以接受IApplicationBuilder实例。然后,您将能够启动DbContext的实例,并执行种子操作,如下所示:

public static void Seed(IApplicationBuilder app)
{
    // Get an instance of the DbContext from the DI container
    using (var context = app.ApplicationServices.GetRequiredService<ApplicationDbContext>())
    {
        // perform database delete
        context.Database.EnsureDeleted;
        //... perform other seed operations
    }
}

11
2018-06-26 05:59



非常感谢!就是这条线 app.ApplicationServices.GetRequiredService<ApplicationDbContext>() 我失踪了。我稍微修改了您的解决方案,将其用作扩展方法。 - Adam H
问题:context.Database.EnsureDeleted()删除__EMMigrationsHistory也!!! - Mohammad Akbari
@MohammadAkbari你似乎在挑选尼特。注意// ...执行其他种子操作行?这显然意味着他可能要执行其他操作。这里解决的问题是将上下文注入种子方法。 - Ketrex
谨防服务定位器反模式,但同时很好的解决方法。我期待EF Core获得更多功能,因此可以用于生产。 - James
我最终使用了 public static IApplicationBuilder Seed(this IApplicationBuilder app) 所以我的创业公司可以使用 app.seed(); - Brian


答案:


假设您使用的是内置DI容器,这是一种可以实现此目的的方法。

在启动类的Configure方法中引用种子方法,并将IApplicationBuilder对象作为参数而不是DbContext传递,如下所示:

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
    //...
    // Put this at the end of your configure method
    DbContextSeedData.Seed(app);
}

接下来,修改种子方法以接受IApplicationBuilder实例。然后,您将能够启动DbContext的实例,并执行种子操作,如下所示:

public static void Seed(IApplicationBuilder app)
{
    // Get an instance of the DbContext from the DI container
    using (var context = app.ApplicationServices.GetRequiredService<ApplicationDbContext>())
    {
        // perform database delete
        context.Database.EnsureDeleted;
        //... perform other seed operations
    }
}

11
2018-06-26 05:59



非常感谢!就是这条线 app.ApplicationServices.GetRequiredService<ApplicationDbContext>() 我失踪了。我稍微修改了您的解决方案,将其用作扩展方法。 - Adam H
问题:context.Database.EnsureDeleted()删除__EMMigrationsHistory也!!! - Mohammad Akbari
@MohammadAkbari你似乎在挑选尼特。注意// ...执行其他种子操作行?这显然意味着他可能要执行其他操作。这里解决的问题是将上下文注入种子方法。 - Ketrex
谨防服务定位器反模式,但同时很好的解决方法。我期待EF Core获得更多功能,因此可以用于生产。 - James
我最终使用了 public static IApplicationBuilder Seed(this IApplicationBuilder app) 所以我的创业公司可以使用 app.seed(); - Brian


您也可以从Startup.cs中使用 ConfigureServices 使ApplicationDbContext可用的方法(将dbcontext注册为服务):

public void ConfigureServices(IServiceCollection services)
{
   var connectionString = Startup.Configuration["connectionStrings:DBConnectionString"];//this line is not that relevant, the most important thing is registering the DbContext
            services.AddDbContext<ApplicationDbContext>(o => o.UseSqlServer(connectionString));
}

然后将ApplicationDbContext作为依赖项添加到您的 Configure 将调用种子扩展方法的方法。

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, ApplicationDbContext myApplicationDbContext)
{
    //...
    myApplicationDbContext.Seed();
}

最后种子方法可以快速检查一个重要的表,因为重建db可能太重了:

public void Seed()
{
 //....      
 if(context.Countries.Any())
   return;
 //...
}

我希望它可以帮助你或其他人,至少作为另一种选择。


3
2018-02-19 23:18





如果要从单独的类库中运行EF代码并执行Seeding,则可以执行以下操作。这是使用TSQL ...

1) 创建一个新的类库。 使用NuGet添加以下依赖项...

Microsoft.AspNetCore
Microsoft.AspNetCore.Identity.EntityFrameworkCore
Microsoft.EntityFrameworkCore.SqlServer
Microsoft.EntityFrameworkCore.Tools

2)将软件包管理器控制台指向此项目并运行...

PM> add-migration Seeder01

然后...

PM> update-database

这会给你一个空的迁移。

3)将更新编写为类似...

using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Migrations;
using System;
using System.Collections.Generic;
using Microsoft.Extensions.Configuration;
using System.IO;

namespace Test02.Data.Migrations
{
    public partial class Seeder01 : Migration
    {

        protected override void Up(MigrationBuilder migrationBuilder)
        {
            string sql = string.Empty;

            sql = "SET IDENTITY_INSERT State ON;";
            sql += "Insert into State (Id, Name) values ";
            sql += "(2, 'NSW'),";
            sql += "(3, 'VIC'),";
            sql += "(4, 'QLD'),";
            sql += "(5, 'SA')";
            sql += ";";
            sql += "SET IDENTITY_INSERT State OFF;";
            migrationBuilder.Sql(sql);

        }

        protected override void Down(MigrationBuilder migrationBuilder)
        {
            string sql = string.Empty;
            sql = "delete State;";
            migrationBuilder.Sql(sql);


        }
    }
}

4)恢复到先前的迁移...

PM> add-migration {PriorMigrationName}

重新加载种子迁移并更新数据库...

PM> add-migration Seeder01
PM> update-database

0
2017-12-19 04:53