我正在使用 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 容器)的 native IoC 并且您收到此错误,请确保将您的 DbContext 注册为 Transient。做
services.AddDbContext<MyContext>(ServiceLifetime.Transient);
或
services.AddTransient<MyContext>();
代替
services.AddDbContext<MyContext>();
AddDbContext 将上下文添加为作用域,这在使用多线程时可能会导致问题。
还有 async / await operations使用异步 lambda 表达式时可能会导致此行为。
将其添加为 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/