当我在集合上使用 Parallel.Foreach 循环时,它会抛出异常 “在上一个操作完成之前,在此上下文上启动了第二个操作。这通常是由使用同一 DbContext 实例的不同线程引起的,但是,不能保证实例成员是线程安全的”
我有使用 .netcore 3.1 和 efcore 2.2 的洋葱架构。 使用具有工作单元设计模式的通用存储库
为unitofwork创建了一个工厂并添加了一个新方法 创建FactoryContext。
public interface IUnitOfWorkFactory { UnitOfWork CreateUnitOfWork(); }
public class UnitOfWorkFactory : IUnitOfWorkFactory
{
private readonly YourDbContext _dbContext;
public UnitOfWorkFactory(YourDbContext dbContext)
{
_dbContext = dbContext;
}
public UnitOfWork CreateUnitOfWork()
{
return new UnitOfWork(_dbContext);
}
}
`
注册到startup.cs文件中
services.AddScoped<IUnitOfWorkFactory, UnitOfWorkFactory>();
注入Service类文件中创建了一个unitofwork对象 每个 ` 公共类 MyService { 私有只读 IUnitOfWorkFactory _unitOfWorkFactory;
public YourService(IUnitOfWorkFactory unitOfWorkFactory)
{
_unitOfWorkFactory = unitOfWorkFactory;
}
public void SendEmails(UserModel user)
{
using (var unitOfWork = _unitOfWorkFactory.CreateUnitOfWork())
{
var emailTemplate = unitOfWork.Templates.GetAllWithNoTracking().Single(x => x.TemplateName= "abc");
}
}
} `
控制器代码
Parallel.ForEach(result, obj => { _myService.SendEmail(obj); });
可能的解决方案是什么
每当调用
UnitOfWorkFactory
时,您的 CreateUnitOfWork
都应该创建一个新的 dbContext。类似的东西
public class UnitOfWorkFactory : IUnitOfWorkFactory
{
private readonly string _connectionString;
public UnitOfWorkFactory(string connectionString)
{
_connectionString= connectionString;
}
public UnitOfWork CreateUnitOfWork()
{
return new UnitOfWork(new YourDbContext (_connectionString));
}
}
这样,每次调用
SendEmails
将使用不同的 DbContext 对象,从而避免并发使用任何上下文。框架应该自动池化与数据库的连接,从而使 DbContext 对象的创建保持相当便宜。
但是,在像这样的并行循环中运行数据库查询通常不是一个好主意。如果可以的话,您通常应该在单个数据库查询中做尽可能多的工作,即添加像
void SendEmails(IEnumerable<UserModel> users)
这样的方法。由于示例不完整并且没有任何作用,因此很难提供具体的建议。