SQL Server Express LocalDB环境下DbInitializer数据未填充到数据库问题
问题根因
你当前的种子数据不生效是触发逻辑设计错误导致的,和懒加载、配置遗漏无关:
Database.EnsureCreated()方法仅在数据库完全不存在、首次创建时才返回true,只要你此前运行过一次程序、数据库已被创建(哪怕表中无任何数据),后续启动时EnsureCreated()都会返回false,直接跳过CreateDbIfNotExists方法,自然不会执行种子插入逻辑。- 你在
Main方法中提前创建了一个独立的服务Scope调用EnsureCreated(),和后续种子逻辑使用的不是同一个上下文实例,也可能存在状态不一致问题。 - 你将代码放到
HomeController中能正常执行,是因为访问页面时手动触发了种子逻辑,不受EnsureCreated()返回值的限制。
修复方案
第一步:修改Program.cs的触发逻辑
删除Main方法中多余的EnsureCreated()判断,直接调用初始化方法即可:
public static void Main(string[] args) { var host = CreateHostBuilder(args).Build(); // 直接调用初始化方法,不再做EnsureCreated返回值判断 CreateDbIfNotExists(host); host.Run(); }
第二步:给DbInitializer增加重复数据校验
避免多次启动程序重复插入相同数据,修改Seed方法的逻辑,插入前先校验数据是否已存在:
public static void Seed(ApplicationDbContext context, IServiceProvider services) { // Seed roles RoleManager<IdentityRole> roleManager = services.GetRequiredService<RoleManager<IdentityRole>>(); string[] roleNames = { "Traffic Manager", "Traffic Officer", "Driver" }; foreach (var roleName in roleNames) { // 角色不存在才创建 if (!roleManager.RoleExistsAsync(roleName).Result) { roleManager.CreateAsync(new IdentityRole() { Name = roleName }).Wait(); } } // Seed test users UserManager<IdentityUser> userManager = services.GetRequiredService<UserManager<IdentityUser>>(); var testUsers = new List<(string Email, string Role)> { ("driver@testwebsite.com", "Driver"), ("officer@testwebsite.com", "Traffic Officer"), ("manager@testwebsite.com", "Traffic Manager") }; foreach (var (email, role) in testUsers) { // 用户不存在才创建 var user = userManager.FindByEmailAsync(email).Result; if (user == null) { user = new IdentityUser() { Email = email, UserName = email, EmailConfirmed = true, TwoFactorEnabled = false }; userManager.CreateAsync(user).Wait(); userManager.AddPasswordAsync(user, "Pa$$word1").Wait(); userManager.AddToRoleAsync(user, role).Wait(); } } // Seed fines,表为空才插入 if (!context.Fines.Any()) { var fine = new Fine[] { new Fine { FineID = Guid.NewGuid().ToString(), OfficerID = Guid.NewGuid().ToString(), DriverID = Guid.NewGuid().ToString(), LicensePlate = "CY4345", VehicleType = VehicleType.Car, Offense = OffenseType.Speeding, OffenseDetail = "85km/h in a 60 zone.", OffenseDate = DateTime.Parse("2017-08-10"), OffenseTime = DateTime.Parse("05:50"), Amount = 50.50m, Outstanding = true }, new Fine { FineID = Guid.NewGuid().ToString(), OfficerID = Guid.NewGuid().ToString(), DriverID = Guid.NewGuid().ToString(), LicensePlate = "CA323566", VehicleType = VehicleType.Bus, Offense = OffenseType.Parking, OffenseDetail = "Parked on red line.", OffenseDate = DateTime.Parse("2018-01-20"), OffenseTime = DateTime.Parse("16:20"), Amount = 350.00m, Outstanding = true }, new Fine { FineID = Guid.NewGuid().ToString(), OfficerID = Guid.NewGuid().ToString(), DriverID = Guid.NewGuid().ToString(), LicensePlate = "CY198450", VehicleType = VehicleType.Car, Offense = OffenseType.Speeding, OffenseDetail = "140km/h in a 100 zone.", OffenseDate = DateTime.Parse("2014-03-12"), OffenseTime = DateTime.Parse("09:15"), Amount = 500.00m, Outstanding = true }, new Fine { FineID = Guid.NewGuid().ToString(), OfficerID = Guid.NewGuid().ToString(), DriverID = Guid.NewGuid().ToString(), LicensePlate = "CA321", VehicleType = VehicleType.Motorcycle, Offense = OffenseType.Speeding, OffenseDetail = "65km/h in a 40 zone.", OffenseDate = DateTime.Parse("2018-10-19"), OffenseTime = DateTime.Parse("15:00"), Amount = 250.00m, Outstanding = true }, new Fine { FineID = Guid.NewGuid().ToString(), OfficerID = Guid.NewGuid().ToString(), DriverID = Guid.NewGuid().ToString(), LicensePlate = "CA974039", VehicleType = VehicleType.Car, Offense = OffenseType.DUI, OffenseDetail = "DUI of alcohol.", OffenseDate = DateTime.Parse("2016-11-11"), OffenseTime = DateTime.Parse("10:10"), Amount = 650.80m, Outstanding = false }, new Fine { FineID = Guid.NewGuid().ToString(), OfficerID = Guid.NewGuid().ToString(), DriverID = Guid.NewGuid().ToString(), LicensePlate = "CY936503", VehicleType = VehicleType.Car, Offense = OffenseType.Parking, OffenseDetail = "Illegally parked on corner.", OffenseDate = DateTime.Parse("2015-06-21"), OffenseTime = DateTime.Parse("11:41"), Amount = 250.00m, Outstanding = true }, new Fine { FineID = Guid.NewGuid().ToString(), OfficerID = Guid.NewGuid().ToString(), DriverID = Guid.NewGuid().ToString(), LicensePlate = "CA99840", VehicleType = VehicleType.Truck, Offense = OffenseType.Speeding, OffenseDetail = "100km/h in a 60 zone.", OffenseDate = DateTime.Parse("2016-06-21"), OffenseTime = DateTime.Parse("09:55"), Amount = 1500.00m, Outstanding = true }, }; context.Fines.AddRange(fine); context.SaveChanges(); } }
可选:强制重置数据
如果你需要重新生成所有种子数据,可先删除LocalDB对应的mdf/ldf文件,或者直接在SSMS中删除现有数据库,重新启动程序即可自动完成库表创建和数据播种。
内容的提问来源于stack exchange,提问作者Jackson Parker
相关产品推荐
相关产品推荐

