我正在尝试使用以下代码为数据库添加种子:
Startup.Configure
:
app.UseCors("AllowAll")
.UseMiddleware<JwtBearerMiddleware>()
.UseAuthentication()
.SeedDatabase() <= here
.UseHttpsRedirection()
.UseDefaultFiles()
.UseMvc()
.UseSpa(SpaApplicationBuilderExtensions => { });
SeedDatabase
方法:
public static IApplicationBuilder SeedDatabase(this IApplicationBuilder app)
{
IServiceProvider serviceProvider = app.ApplicationServices.CreateScope().ServiceProvider;
try
{
UserManager<ApplicationUser> userManager = serviceProvider.GetService<UserManager<ApplicationUser>>();
RoleManager<IdentityRole> roleManager = serviceProvider.GetService<RoleManager<IdentityRole>>();
IConfiguration configuration = serviceProvider.GetService<IConfiguration>();
ThePLeagueContext dbContext = serviceProvider.GetService<ThePLeagueContext>();
DataBaseInitializer.SeedUsers(userManager, roleManager, configuration, dbContext);
DataBaseInitializer.SeedTeams(dbContext);
}
catch (Exception ex)
{
ILogger<Program> logger = serviceProvider.GetRequiredService<ILogger<Program>>();
logger.LogError(ex, "An error occurred while seeding the database.");
}
return app;
}
一切正常,直到我添加了ThePLeagueContext dbContext = serviceProvider.GetService<ThePLeagueContext>();
,然后DataBaseInitializer.SeedTeams(dbContext)
DataBaseInitializer.SeedTeams(dbContext)
:
public static async void SeedTeams(ThePLeagueContext dbContext)
{
List<Team> teams = new List<Team>();
// 7 because we have 7 leagues
for (int i = 0; i < 7; i++)...
if (dbContext.Teams.Count() < teams.Count)
{
foreach (Team newTeam in teams)
{
await dbContext.Teams.AddAsync(newTeam);
await dbContext.SaveChangesAsync();
}
}
}
当我尝试使用上述代码为数据库添加种子时,出现以下异常:
System.InvalidOperationException:'在上一个操作完成之前,第二个操作在此上下文上开始。这通常是由使用同一DbContext实例的不同线程引起的,但是不能保证实例成员是线程安全的。如果是这种情况,也可能是因为在客户端上评估了嵌套查询,如果是这种情况,请重写查询以避免嵌套调用。
我的数据库上下文已在LifeTime中注册Scoped
。
我发现了两种解决方法:
Transient
为种子时,问题就消失了。但是,这会导致应用程序出现其他问题,因此我无法使用Transient
DatabaseInitializer.SeedTeams(dbContext)
从DatabaseInitializer.SeedUsers(...)
方法内部调用时,这也有效,我不知道为什么。DatabaseInitializer.SeedUsers(...)
方法:
public async static void SeedUsers(UserManager<ApplicationUser> userManager, RoleManager<IdentityRole> roleManager, IConfiguration configuration, ThePLeagueContext dbContext)
{
string[] roles = new string[] { AdminRole, SuperUserRole, UserRole };
foreach (string role in roles)
{
if (!roleManager.Roles.Any(r => r.Name == role))
{
IdentityRole newRole = new IdentityRole
{
Name = role,
NormalizedName = role.ToUpper()
};
await roleManager.CreateAsync(newRole);
if (role == AdminRole)
{
await roleManager.AddClaimAsync(newRole, new Claim(Permission, ModifyPermission));
}
else if (role == SuperUserRole)
{
await roleManager.AddClaimAsync(newRole, new Claim(Permission, RetrievePermission));
}
else
{
await roleManager.AddClaimAsync(newRole, new Claim(Permission, ViewPermission));
}
}
}
ApplicationUser admin = new ApplicationUser()...
ApplicationUser sysAdmin = new ApplicationUser()...;
PasswordHasher<ApplicationUser> password = new PasswordHasher<ApplicationUser>();
if (!userManager.Users.Any(u => u.UserName == admin.UserName))
{
string hashed = password.HashPassword(admin, configuration["ThePLeagueAdminInitPassword"]);
admin.PasswordHash = hashed;
await userManager.CreateAsync(admin);
await userManager.AddToRoleAsync(admin, AdminRole);
}
if (!userManager.Users.Any(u => u.UserName == sysAdmin.UserName))
{
string hashed = password.HashPassword(sysAdmin, configuration["ThePLeagueAdminInitPassword"]);
sysAdmin.PasswordHash = hashed;
await userManager.CreateAsync(sysAdmin);
await userManager.AddToRoleAsync(sysAdmin, AdminRole);
}
SeedTeams(dbContext);
}
有什么办法可以使用两个单独的静态异步方法为数据库设置种子并保持上下文范围?
所以我喜欢让事情井然有序。因此,我会做类似的事情:
public static class SeedData
{
public static void Populate(IServiceProvider services)
{
ApplicationDbContext context = services.GetRequiredService<ApplicationDbContext>();
if (!context.SomeDbSet.Any())
{
// ...code omitted for brevity...
);
context.SaveChanges();
}
}
public static class IdentitySeedData
{
public static async Task Populate(IServiceProvider services)
{
UserManager<ApplicationUser> userManager = services.GetService<UserManager<ApplicationUser>>();
RoleManager<IdentityRole> roleManager = services.GetService<RoleManager<IdentityRole>>();
IConfiguration configuration = services.GetService<IConfiguration>();
ApplicationDbContext context = services.GetRequiredService<ApplicationDbContext>();
if (!context.Users.Any())
{
// ...code omitted for brevity...
await userManager.CreateAsync(sysAdmin);
await userManager.AddToRoleAsync(sysAdmin, AdminRole);
);
context.SaveChanges();
}
}
然后是最重要的一个:
public static class DatabaseInitializer
{
public static void Initialize(IServiceProvider services)
{
IdentitySeedData.Populate(services).Wait();
SeedData.Populate(services);
}
}
免责声明:我没有运行代码。因此,如果需要进行一些调整,请告诉我。我会进行调整。要进行测试很耗时。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句