C# 如何在实体框架核心3.0中播种?
我正在尝试使用ASP.NET CORE 3.0和EF CORE为数据库添加一些数据 我已经创建了DbContext,并且根据,甚至(我找不到关于这个主题的任何突破性的更改)C# 如何在实体框架核心3.0中播种?,c#,entity-framework-core,asp.net-core-3.0,C#,Entity Framework Core,Asp.net Core 3.0,我正在尝试使用ASP.NET CORE 3.0和EF CORE为数据库添加一些数据 我已经创建了DbContext,并且根据,甚至(我找不到关于这个主题的任何突破性的更改) 模型创建时受保护的覆盖无效(ModelBuilder ModelBuilder) { modelBuilder.Entity().HasData( 新乐队() { Id=Guid.Parse(“e96bf6d6-3c62-41a9-8ecf-1bd23af931c9”), Name=“SomeName”, CreatedOn
模型创建时受保护的覆盖无效(ModelBuilder ModelBuilder)
{
modelBuilder.Entity().HasData(
新乐队()
{
Id=Guid.Parse(“e96bf6d6-3c62-41a9-8ecf-1bd23af931c9”),
Name=“SomeName”,
CreatedOn=newdatetime(1980,2,13),
Description=“SomeDescription”
});
基于模型创建(modelBuilder);
}
这并没有达到我预期的效果:启动应用程序时没有种子(即使在调试期间从某处调用了该方法)
但是,如果添加迁移,迁移将包含相应的insert语句(这不是我要寻找的种子类型)
问题:在应用程序启动时执行数据库种子的正确方法是什么
通过对数据库进行种子设定,我的意思是,我希望每次启动应用程序时,都能确保某些表中的某些数据
我可以选择创建一个种子类并在数据库之后处理它。使用自定义代码进行迁移,但这似乎是一个解决方法,因为文档指定应使用OnModelCreating来种子数据)
因此,在阅读了答案并重新阅读了文档之后,我的理解是,“种子”指的是可以在数据模型旁边进行的“初始化”(这就是为什么感觉奇怪的原因——将模型创建与数据种子部分混合在一起)。如果您想在应用程序启动时种子,在应用程序启动方法中,可以使用条件检查来检查所需的数据,如果没有返回,则将这些类添加到上下文中并保存更改 EF Core中的种子是为迁移而设计的,它的初始化数据用于数据库,而不是用于应用程序运行时。如果你想要一组数据不变,那么考虑使用另一种方法吗?例如,通过带有字段检查的属性进行内存缓存,将其保持为xml/json格式 您可以在应用程序启动时使用删除/创建语法,但它通常不受欢迎,因为状态缺乏持久性
不幸的是,对于您想要的内容,它必须是一个解决方案,因为它不在EF的预期功能范围内。我不认为
OnModelCreating()
是为数据库播种的最佳场所。我认为这完全取决于您希望何时运行播种逻辑。您说过希望在应用程序启动时运行种子设定,而不管数据库是否有迁移更改
我将创建一个扩展方法,以钩住Startup.cs类中的Configure()
方法:
Startup.cs:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.MigrateAndSeedDb(development: true);
}
else
{
app.MigrateAndSeedDb(development: false);
}
app.UseHttpsRedirection();
...
MigrateAndSeedDb.cs
public static void MigrateAndSeedDb(this IApplicationBuilder app, bool development = false)
{
using (var serviceScope = app.ApplicationServices.GetRequiredService<IServiceScopeFactory>().CreateScope())
using (var context = serviceScope.ServiceProvider.GetService<GatewayDbContext>())
{
//your development/live logic here eg:
context.Migrate();
if(development)
context.Seed();
}
}
private static void Migrate(this GatewayDbContext context)
{
context.Database.EnsureCreated();
if (context.Database.GetPendingMigrations().Any())
context.Database.Migrate();
}
private static void Seed(this GatewayDbContext context)
{
context.AddOrUpdateSeedData();
context.SaveChanges();
}
若你们有复杂的种子数据,那个么使用默认的EF核心特性并不是一个好主意。例如,无法根据配置或系统环境添加种子数据 我正在使用自定义服务和依赖注入来添加种子数据,并在应用程序启动时为上下文应用任何挂起的迁移。我将分享我的定制服务,希望它有助于: IDbInitializer.cs
公共接口初始值设定项
{
///
///将上下文的所有挂起迁移应用于数据库。
///如果数据库不存在,将创建该数据库。
///
void初始化();
///
///向数据库添加一些默认值
///
void SeedData();
}
DbInitializer.cs
公共类DbInitializer:IDbInitializer{
专用读写器ViceScopeFactory\u scopeFactory;
公共数据库初始值设定项(IServiceScopeFactory范围工厂){
这。_scopeFactory=scopeFactory;
}
公共无效初始化(){
使用(var serviceScope=\u scopeFactory.CreateScope()){
使用(var context=serviceScope.ServiceProvider.GetService()){
context.Database.Migrate();
}
}
}
公共数据(){
使用(var serviceScope=\u scopeFactory.CreateScope()){
使用(var context=serviceScope.ServiceProvider.GetService()){
//添加管理员用户
如果(!context.Users.Any()){
var adminUser=新用户{
IsActive=true,
Username=“admin”,
Password=“admin1234”,//应为哈希
SerialNumber=Guid.NewGuid().ToString()
};
context.Users.Add(adminUser);
}
context.SaveChanges();
}
}
}
}
要使用此服务,您可以将其添加到服务集合中:
//StartUp.cs--配置服务方法
services.AddScoped()
因为我想在每次程序启动时使用此服务,所以我使用注入式服务的方式如下:
//StartUp.cs--配置方法
var scopeFactory=app.ApplicationServices.GetRequiredService();
使用(var scope=scopeFactory.CreateScope()){
var dbInitializer=scope.ServiceProvider.GetService();
初始化();
dbInitializer.SeedData();
}
您可以对其使用迁移。只需创建一个新的迁移(不需要事先更改模型类)。生成的迁移类将具有empty Up()和Down()方法。
你可以在那里播种。比如:
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.Sql("your sql statement here...");
}
就这样。就这样
public class Program
{
public static void Main(string[] args)
{
var host = CreateHostBuilder(args).Build();
using (var scope = host.Services.CreateScope())
{
var services = scope.ServiceProvider;
try
{
SeedDatabase.Initialize(services);
}
catch (Exception ex)
{
var logger = services.GetRequiredService<ILogger<Program>>();
logger.LogError(ex, "An error occured seeding the DB");
}
}
host.Run();
}
public static IHostBuilder CreateHostBuilder(string[] args)
{
var hb = Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
return hb;
}
}
公共类
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.Sql("your sql statement here...");
}
public class Program
{
public static void Main(string[] args)
{
var host = CreateHostBuilder(args).Build();
using (var scope = host.Services.CreateScope())
{
var services = scope.ServiceProvider;
try
{
SeedDatabase.Initialize(services);
}
catch (Exception ex)
{
var logger = services.GetRequiredService<ILogger<Program>>();
logger.LogError(ex, "An error occured seeding the DB");
}
}
host.Run();
}
public static IHostBuilder CreateHostBuilder(string[] args)
{
var hb = Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
return hb;
}
}
public static class SeedDatabase
{
public static void Initialize(IServiceProvider serviceProvider)
{
using (var context = new HospitalManagementDbContext(serviceProvider.GetRequiredService<DbContextOptions<HospitalManagementDbContext>>()))
{
if (context.InvestigationTags.Any())
{
return;
}
context.InvestigationTags.AddRange(
new Models.InvestigationTag
{
Abbreviation = "A1A",
Name = "Alpha-1 Antitrypsin"
},
new Models.InvestigationTag
{
Abbreviation = "A1c",
Name = "Hemoglobin A1c"
},
new Models.InvestigationTag
{
Abbreviation = "Alk Phos",
Name = "Alkaline Phosphatase"
}
);
context.SaveChanges();
}
}
}