将所有表转换为在标识列中开始使用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类的最后一行。
那我在做什么错了?
答案 0 :(得分:3)
new SeedTest()
未初始化其_context
字段。您可以在DatabaseInitializer
上使用DI来将SeedTest
与MyDbContext
实例化。
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的更多信息。