我正在使用Entity Framework Core进行ASP.Net Core 2.0项目
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="2.0.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="2.0.0" PrivateAssets="All" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="2.0.0"/>
在我的一种列表方法中,我收到此错误:
InvalidOperationException: A second operation started on this context before a previous operation completed. Any instance members are not guaranteed to be thread safe.
Microsoft.EntityFrameworkCore.Internal.ConcurrencyDetector.EnterCriticalSection()
这是我的方法:
[HttpGet("{currentPage}/{pageSize}/")]
[HttpGet("{currentPage}/{pageSize}/{search}")]
public ListResponseVM<ClientVM> GetClients([FromRoute] int currentPage, int pageSize, string search)
{
var resp = new ListResponseVM<ClientVM>();
var items = _context.Clients
.Include(i => i.Contacts)
.Include(i => i.Addresses)
.Include("ClientObjectives.Objective")
.Include(i => i.Urls)
.Include(i => i.Users)
.Where(p => string.IsNullOrEmpty(search) || p.CompanyName.Contains(search))
.OrderBy(p => p.CompanyName)
.ToPagedList(pageSize, currentPage);
resp.NumberOfPages = items.TotalPage;
foreach (var item in items)
{
var client = _mapper.Map<ClientVM>(item);
client.Addresses = new List<AddressVM>();
foreach (var addr in item.Addresses)
{
var address = _mapper.Map<AddressVM>(addr);
address.CountryCode = addr.CountryId;
client.Addresses.Add(address);
}
client.Contacts = item.Contacts.Select(p => _mapper.Map<ContactVM>(p)).ToList();
client.Urls = item.Urls.Select(p => _mapper.Map<ClientUrlVM>(p)).ToList();
client.Objectives = item.Objectives.Select(p => _mapper.Map<ObjectiveVM>(p)).ToList();
resp.Items.Add(client);
}
return resp;
}
我有点迷茫,尤其是因为它在本地运行时可以运行,但是当我部署到我的登台服务器(IIS 8.5)时,我得到了这个错误,并且运行正常。当我增加一个模型的最大长度后,该错误开始出现。我还更新了相应 View 模型的最大长度。而且还有许多其他列表方法非常相似,并且它们都在起作用。
我正在运行一个Hangfire作业,但是此作业没有使用相同的实体。我认为这就是很重要的。关于什么可能导致此的任何想法?
最佳答案
我不确定您是否正在使用IoC和依赖注入(inject)在任何可能使用DbContext的地方进行解析。如果这样做,并且您正在使用.NET Core(或任何其他IoC-Container)中的 native IoC,并且遇到此错误,请确保将DbContext注册为 transient 。做
services.AddTransient<MyContext>();
要么
services.AddDbContext<MyContext>(ServiceLifetime.Transient);
代替
services.AddDbContext<MyContext>();
AddDbContext将上下文添加为作用域,这可能在使用多个线程时引起麻烦。
当使用异步lambda表达式时,async / await operations也可能导致此行为。
将其添加为 transient 也有其缺点。您将无法在使用上下文的多个类上对某些实体进行更改,因为每个类都将获得自己的DbContext实例。
对此的简单解释是
DbContext
实现不是线程安全的。您可以阅读有关此here的更多信息关于c# - Entity Framework 核心: A second operation started on this context before a previous operation completed,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/48767910/