linux 上的 Dotnet 核心 1.1:使用 EF Core 播种数据时有什么比其他方法更好的方法吗?

Dotnet core 1.1 on linux: Any particular way thats better than others when seeding data with EF Core?

我正在考虑只进行一次迁移,然后在该迁移中播种数据。我不确定我是否希望播种成为我迁移的一部分,也许有一天我想要一个干净的石板。

我上次 asp.net 大约一年前 windows 我有以下实现:

using System.Collections.Generic;
using System.Data.Entity.Validation;
using Mentor.Models;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.EntityFramework;
/**
 * Author: matti
 */
namespace Mentor.Migrations
{
    using System;
    using System.Data.Entity;
    using System.Data.Entity.Migrations;
    using System.Linq;

    internal sealed class Configuration : DbMigrationsConfiguration<Mentor.Models.ApplicationDbContext>
    {
        public Configuration()
        {
            /*if (System.Diagnostics.Debugger.IsAttached == false)
               System.Diagnostics.Debugger.Launch();*/
            AutomaticMigrationsEnabled = true;
            AutomaticMigrationDataLossAllowed = true;
            ContextKey = "Mentor.Models.ApplicationDbContext";
        }

        protected override void Seed(Mentor.Models.ApplicationDbContext context)
        {
            try
            {
                var passwordHasher = new PasswordHasher();
                User user1 = new User()
                {
                    UserName = "mattinielsen5@hotmail.com",
                    PasswordHash = passwordHasher.HashPassword("Denherpderp21!"),
                    FirstName = "Matti andreas",
                    LastName = "Nielsen",
                    Age = 24,
                    ProfileText = "Lorem ipsum dolor sit amet, minimum delicatissimi ad eos, " +
                                  "ne veniam eirmod voluptatibus vel, ne eam facilisi inciderint. " +
                                  "Ex eleifend recteque delicatissimi eos, ut erat posse etiam pri." +
                                  " Ei qui commune vivendum legendos, augue accusata in vim, mei at" +
                                  " bonorum pericula definitionem. Has ornatus aliquando vulputate " +
                                  "at, nonumes docendi in mel. Ne duo recusabo percipitur, et nam " +
                                  "vitae nostrud cotidieque, cibo liber mel te.",
                    IsMentor = true,
                    IsMentee = false,
                    UndefinedInterests = new List<Interest>
                    {

                    },
                    MentorInterests = new List<Interest>
                    {

                    },
                    ... blabla alot of entities ...
                context.SaveChanges();
            }
            catch (DbEntityValidationException e)
            {
                //some error handling
            }
        }
    }
}

所以我想要像种子方法这样的东西,所以我正在考虑根据开发等环境变量在 startup.cs 中调用我自己的种子方法。我的问题是,你们是怎么做的 - 或者你们会怎么做??

编辑:

我正在考虑这样做,在创建模型时:

protected override void OnModelCreating(ModelBuilder modelBuilder) 
  {
    //One-to-one
     modelBuilder.Entity<Account>().HasOne(a => a.Player).WithOne(p =>   p.Account).HasForeignKey<Player>(p => p.AccountForeignKey);
     modelBuilder.Entity<Group>().HasOne(g => g.Role).WithOne(r => r.Group).HasForeignKey<Role>(r => r.GroupForeignKey);
    modelBuilder.Entity<GameEvent>().HasOne(e => e.Event);
    modelBuilder.Entity<GameEvent>().HasOne(e => e.Game);
    modelBuilder.Entity<TeamEvent>().HasOne(e => e.Event);
    modelBuilder.Entity<TeamEvent>().HasOne(e => e.Team);
    modelBuilder.Entity<GroupEvent>().HasOne(e => e.Event);
    modelBuilder.Entity<GroupEvent>().HasOne(e => e.Group);

    //one-to-many
    modelBuilder.Entity<Player>().HasMany(p => p.Integrations).WithOne(i => i.Player);
    modelBuilder.Entity<Player>().HasMany(p => p.Followers);
    modelBuilder.Entity<Player>().HasMany(p => p.Activities).WithOne(a => a.Player);
    modelBuilder.Entity<Game>().HasMany(g => g.GameEvents).WithOne(ge => ge.Game);
    modelBuilder.Entity<Game>().HasMany(g => g.Teams).WithOne(t => t.Game);
    modelBuilder.Entity<Team>().HasMany(t => t.TeamEvents).WithOne(te => te.Team);
    modelBuilder.Entity<Group>().HasMany(g => g.GroupEvents);

    //many to many
    modelBuilder.Entity<PlayerGames>().HasKey(pg => new {pg.PlayerId, pg.GameId});
    modelBuilder.Entity<PlayerTeams>().HasKey(pt => new {pt.PlayerId, pt.TeamId});
    modelBuilder.Entity<PlayerGroups>().HasKey(pg => new {pg.PlayerId, pg.GroupId});

    //discriminator values
    modelBuilder.Entity<Event>()
        .HasDiscriminator<string>("Type")
        .HasValue<GameEvent>("GameEvent")
        .HasValue<GroupEvent>("GroupEvent")
        .HasValue<TeamEvent>("TeamEvent");

    CALLING SEED DATA DOWN HERE, that should be fine???
}

推荐的方法是运行在Startup.Configure()的服务范围内做种代码。

是这样的:

using (var serviceScope = app.ApplicationServices.GetRequiredService<IServiceScopeFactory>().CreateScope())
{
       var context = serviceScope.ServiceProvider.GetService<MyContext>();       
       context.Database.Migrate();
       context.EnsureSeedData();
 }

您可以在下面link.

查看更多详细信息

Implementing Seeding EF Core 1.0

同意@Sampath 的回答,但要添加的内容太多,无法快速编辑他的回答。几点观察:

  1. 非常相似(重复?)的问题,例如
  2. 这个问题+答案和其他问题似乎特定于 EF Core。这就是我的情况。
  3. 特别是 OP 向我们展示了他们以前的实现; DbMigrationsConfiguration<TContext>.Seed() 方法(来自 EF 6); @Sampath 的 link 使 the same observation —— 所以读者从 EF 5/6 迁移到 EF Core 一定很常见;我也是这样。
  4. @Sampath 的回答集中在 GetService() 返回的新 serviceScope 的 using,如 @Sampath's link, which is a pattern created in response to this git issue, where the user had already disposed of their DbContext. This pattern is also seen in other answers, all of which ( 中所建议)调用 GetService()GetRequiredService() 和我觉得没必要。

我的回答:

您可以直接从依赖注入中获取 DbContext Startup.Configure(...)

@Sampath 和两个 link 中的任何一个都没有解释 context.EnsureSeedData() 中发生的事情(也许这对一些读者来说是显而易见的,但对我来说不是)。所以我在下面解释

我相信 intro to EF (Core) MVC 提供了解决方案;它创建:

  1. 静态classDbInitializer
  2. a class ... 有一个名为 Initialize 的静态函数,其中 "ensures the seed data is there"。因此,它的细节(见下文)有助于替代 EnsureSeedData() 方法的实现;也许其他用户会发现它有帮助
  3. 一个静态函数...传递给一个DbContext(大概未处理;如果你已经处理了它,你应该遵循@Sampath的回答 and/or 其他 ),并可能引入一个新的 using
  4. 一个静态函数...在 Startup.Configure() 中调用(最后?)——与@Sampath 的
  5. 相同

静态 Initialize 又名 "ensure seed" 函数执行以下关键操作:

  1. 确保创建数据库:context.Database.EnsureCreated();这实现了 "ensure"
  2. 检查一个 table 中的任何行(您可能想检查 each table,您可能想检查 specific行),如果有行(假设这个函数已经执行,所以return;这意味着它是"idempotent"并且可以在每次启动时安全地执行多次,但只能播种一次
  3. 如果没有任何行;它插入一些行;这实现了 "seed";保证有行(通过添加对象文字并调用 DbContext.SaveChanges()

如此处所示:

public static class DbInitializer
{
    public static void Initialize(SchoolContext context)
    {
        context.Database.EnsureCreated();

        // Look for any students.
        if (context.Students.Any())
        {
            return;   // DB has been seeded
        }

        var students = new Student[]
        {
            new Student{FirstMidName="Carson",LastName="Alexander",EnrollmentDate=DateTime.Parse("2005-09-01")}, ...
        };
        foreach (Student s in students)
        {
            context.Students.Add(s);
        }
        context.SaveChanges();
        ...

然后使用依赖注入 DbContext 调用函数,如下所示:

First, add the context to the method signature so that ASP.NET dependency injection can provide it to your DbInitializer class.2

public void Configure(..., ..., SchoolContext context)
{

Then call your DbInitializer.Initialize method at the end of the Configure method.

    ...
    DbInitializer.Initialize(context);
}