Asp.Net Core-如何播种数据-未将对象引用设置为对象的实例

时间:2019-06-19 23:28:13

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

将所有表转换为在标识列中开始使用Guid类型之后,我无法为数据添加种子,因此我简化了很多代码以对错误进行本地化,并以种子类结束,如下所示:

public class SeedTest
{
    private readonly MyDbContext _context;

    public SeedTest(MyDbContext context)
    {
        _context = context;
    }

    public async Task SeedTest()
    {
        Values value1 = new Values
        {
            Id = Guid.Parse("29c48913-1b5c-47b8-g144-08d6d2273deb"),
            ValueName = "value 1",
            Created = DateTime.Now
        };

        _context.Values.Add(value1);

        await _context.SaveChangesAsync();
    }

    public SeedTest()
    {
    }
}

该类是从另一个类中调用的:

public interface IDatabaseInitializer
{
    Task SeedAsync();
}

public class DatabaseInitializer : IDatabaseInitializer
{
    public async Task SeedAsync()
    {
            SeedTest _seedTest = new SeedTest();
            await _seedTest.SeedTest();
    }
}

从startup.cs调用

    public class Startup
    {
        public IConfiguration Configuration { get; }
        private readonly IHostingEnvironment _hostingEnvironment;

        public Startup(IConfiguration configuration, IHostingEnvironment env)
        {
            Configuration = configuration;
            _hostingEnvironment = env;
        }

        public void ConfigureServices(IServiceCollection services)
        {
            ...
            services.AddMyDbContext<MyDbContext>(options =>
                options.UseSqlServer("ConnectionStrings:MyCn"));
            ...
            // DB Seeding
            services.AddTransient<IDatabaseInitializer, DatabaseInitializer>();
            ...
            ...
     }

这是从program.cs触发的方式

public class Program
{

    public static void Main(string[] args)
    {
        var host = BuildWebHost(args);

        using (var scope = host.Services.CreateScope())
        {
            var services = scope.ServiceProvider;
            try
            {
                var databaseInitializer = services.GetRequiredService<IDatabaseInitializer>();
                databaseInitializer.SeedAsync().Wait();
            }
            catch (Exception ex)
            {
                var logger = services.GetRequiredService<ILogger<Program>>();
                logger.LogCritical(LoggingEvents.INIT_DATABASE, ex, LoggingEvents.INIT_DATABASE.Name);
            }
        }

        host.Run();
    }

    public static IWebHost BuildWebHost(string[] args) =>
                WebHost.CreateDefaultBuilder(args)
                    .UseStartup<Startup>()
                    .Build();
}

不幸的是,该实现没有在数据库中植入任何数据,我可以在日志文件中找到唯一的错误,它说:

  

System.NullReferenceException:对象引用未设置为实例   一个对象。它指向SeedTest类的最后一行。

那我在做什么错了?

3 个答案:

答案 0 :(得分:3)

new SeedTest()未初始化其_context字段。您可以在DatabaseInitializer上使用DI来将SeedTestMyDbContext实例化。

public class DatabaseInitializer : IDatabaseInitializer
{
    private readonly MyDbContext _context;

    public DatabaseInitializer(MyDbContext context)
    {
        _context = context;
    }

    public async Task SeedAsync()
    {
        SeedTest _seedTest = new SeedTest(_context);
        await _seedTest.SeedTest();
    }
}

答案 1 :(得分:1)

您正在显式更新DatabaseInitialize中的SeedTest实例,而DatabaseInitialize实例是由依赖项注入服务创建的。在具有正确作用域的服务中注册SeedTest类,然后让依赖项注入完成它的工作。

在ConfigureServices中添加类似内容

services.AddTransient<SeedTest>();

修改DatabaseInitializer

public class DatabaseInitializer : IDatabaseInitializer{
     private readonly SeedTest _seedTest;
     public DatabaseInitializer(SeedTest seedTest) 
     {
          _seedTest = seedTest;
     }

     public async Task SeedAsync()
     {
         await _seedTest.SeedTest();
     }
}

删除无参数的SeedTest构造函数,并确保注册的MyDbContext类型是另一个构造函数中传递的类型,因为您同时具有MyDbContext和DbContext。

答案 2 :(得分:0)

您可以尝试一下,我已经为此示例使用了.net core 2.2-

MyDbContext.cs

public class MyDbContext : DbContext
    {
        public MyDbContext(DbContextOptions<MyDbContext> options) : base(options)
        {
            Database.EnsureCreated();
        }

        public DbSet<Values> Values { get; set; }
    }

SeedTest.cs

public class SeedTest
    {
        private readonly MyDbContext _context;

        public SeedTest(MyDbContext context)
        {
            _context = context;
        }

        public async Task SeedTest1()
        {
            Values value1 = new Values
            {
                Id = Guid.Parse("AFE1052A-A694-48AF-AA77-56D2D945DE31"),
                ValueName = "value 1",
                Created = DateTime.Now
            };

            _context.Values.Add(value1);

            var value  = await _context.SaveChangesAsync();
        }

        public SeedTest()
        {
        }
    }

服务

public interface IDatabaseInitializer
    {
        Task SeedAsync();
    }

    public class DatabaseInitializer : IDatabaseInitializer
    {
        private readonly MyDbContext _cotext;

       // Inject DbContext 
        public DatabaseInitializer(MyDbContext dbContext)
        {
            _cotext = dbContext;
        }
        public async Task SeedAsync()
        {
            // Object with contructor which having DbContext parameter
            SeedTest _seedTest = new SeedTest(_cotext);
            await _seedTest.SeedTest1();
        }
    }

startup.cs

 services.AddTransient<IDatabaseInitializer, DatabaseInitializer>();
 services.AddDbContext<MyDbContext>(option=> option.UseSqlServer("Data Source=localhost;Initial Catalog=StackOverFlow1;Integrated Security=True"));

program.cs

public class Program
    {
        public static void Main(string[] args)
        {
            var host = CreateWebHostBuilder(args).Build();

            using (var scope = host.Services.CreateScope())
            {
                var services = scope.ServiceProvider;
                try
                {
                    var databaseInitializer = services.GetRequiredService<IDatabaseInitializer>();
                    databaseInitializer.SeedAsync().Wait();
                }
                catch (Exception ex)
                {
                }
            }
            host.Run();
        }

        public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
                .UseStartup<Startup>();
    }

您可以阅读有关seed data的更多信息。