Linux上的Dotnet核心1.1:在使用EF Core播种数据时,有什么特别的方式比其他方式更好?

时间:2016-11-19 13:46:02

标签: c# entity-framework asp.net-core entity-framework-core seeding

我正在考虑进行迁移,并在迁移中播种数据。我不确定我是否希望种子成为我的迁移的一部分,也许有时候我想要一个干净的石板。

上一次我在大约一年前在Windows上做过asp.net我有以下实现:

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

2 个答案:

答案 0 :(得分:3)

建议的方法是在Startup.Configure()

的服务范围内运行种子代码

它是这样的:

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

您可以在以下链接中查看有关此内容的更多详细信息。

Implementing Seeding EF Core 1.0

答案 1 :(得分:0)

同意@ Sampath的答案,但是为了快速编辑他的答案而添加了太多内容。一些观察结果:

  1. 非常相似(重复?)问题,例如this one
  2. 这个问题+答案和其他似乎是EF Core特有的。那是我的情况。
  3. 特别是OP向我们展示了他们以前的实施; DbMigrationsConfiguration<TContext>.Seed()方法(来自EF 6); @ Sampath的链接使the same observation - 所以读者必须通常从EF 5/6迁移到EF Core;这也是我的情况。
  4. @ Sampath的回答侧重于从using返回的新serviceScope的GetService(),如@Sampath's link中所述,这是在response to this git issue中创建的模式,其中用户已经处理了他们的DbContext 。这种模式也出现在其他答案中,所有这些(except for this one)调用GetService()GetRequiredService(),我认为这不是必要的。
  5. 我的回答:

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

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

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

    1. 静态类DbInitializer
    2. 一个类...有一个名为Initialize的静态函数,“确保种子数据存在”。因此,其详细信息(见下文)有助于替代EnsureSeedData()方法的实施;也许其他用户会觉得有用
    3. 一个静态函数......传递DbContext(大概是没有被处理;如果你已经处理它,你应该跟随@ Sampath的回答和/或其他人,which will GetService()),并可能引入新的using
    4. 一个静态函数...在Startup.Configure()中调用(最后?) - 与@ Sampath的
    5. 相同

      静态Initialize又名“确保种子”功能可以完成以下关键事项:

      1. 确保创建数据库:context.Database.EnsureCreated();这实现了“确保”
      2. 检查一个表中的任何行(您可能要检入每个表,您可能要检查特定的行)以及是否有行(假设这个函数已经执行了,所以return;这意味着它是“幂等的”并且可以在每次启动时安全地执行多次,但只能播种一次
      3. 如果任何行;它会插入一些行;这实现了“种子”;保证有行(通过添加对象文字和调用DbContext.SaveChanges()
      4. 如下所示:

        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调用该函数,如下所示:

          

        首先,将上下文添加到方法签名中,以便ASP.NET依赖项注入可以将它提供给DbInitializer类.2

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

        然后在结束时调用你的DbInitializer.Initialize方法   配置方法。

            ...
            DbInitializer.Initialize(context);
        }