Ядро Entity Framework: вторая операция, начатая в этом контексте до завершения предыдущей операции
Я работаю над ASP.Net проект Core 2.0 с использованием Entity Framework Core
<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) он получает эту ошибку, и он работал нормально. Ошибка начала появляться после увеличения максимальной длины одной из моих моделей. Я также обновлен максимальная длина соответствующей модели представления. И есть много других методов, которые очень похожи и они работают.
у меня была работа Hangfire, но эта работа не использует ту же сущность. Это все, что я могу считать важным. Есть идеи, что могло быть причиной этого?
Спасибо за помощь
4 ответов
исключение означает, что _context
используется двумя потоками одновременно; либо двумя потоками в одном запросе, либо двумя запросами.
ваш _context
объявлен static, может быть? Этого не должно быть.
или ты называешь GetClients
несколько раз в одном запросе из другого места в вашем коде?
возможно, вы уже делаете это, но в идеале, вы будете использовать внедрение зависимостей для DbContext
, что означает, что вы будете использовать AddDbContext
in ваш стартап.cs, и ваш конструктор контроллера будет выглядеть примерно так:
private readonly MyDbContext _context; //not static
public MyController(MyDbContext context) {
_context = context;
}
если ваш код не такой, покажите нам, и, возможно, мы сможем помочь дальше.
Я не уверен, что вы используете IoC и инъекцию зависимостей для решения вашего DbContext, где бы он ни использовался. Если вы используете собственный IoC из .NET Core,обязательно зарегистрируйте DbContext как переходный. Do
services.AddTransient<MyContext>();
или
services.AddDbContext<MyContext>(ServiceLifetime.Transient);
вместо
services.AddDbContext<MyContext>();
AddDbContext добавляет контекст как область видимости, что может вызвать проблемы при работе с несколькими потоками.
и асинхронный / ждут операции может вызвать такое поведение при использовании асинхронных лямбда-выражений.
добавление его в качестве переходного также имеет свои недостатки. Вы не сможете вносить изменения в некоторую сущность по нескольким классам, использующим контекст, потому что каждый класс получит свой собственный экземпляр вашего DbContext.
я столкнулся с той же проблемой, но причина не была ни одной из перечисленных выше. Я создал задачу, создал область внутри задачи и попросил контейнер получить службу. Это сработало хорошо, но затем я использовал вторую службу внутри задачи, и я забыл также попросить ее в новую область. Из-за этого 2-я служба использовала DbContext, который уже был удален.
Task task = Task.Run(() =>
{
using (var scope = serviceScopeFactory.CreateScope())
{
var otherOfferService = scope.ServiceProvider.GetService<IOfferService>();
// everything was ok here. then I did:
productService.DoSomething(); // (from the main scope) and this failed because the db context associated to that service was already disposed.
...
}
}
Я должен был сделать это:
var otherProductService = scope.ServiceProvider.GetService<IProductService>();
otherProductService.DoSomething();
мне удалось заставить его работать снова. Это не имеет большого смысла, но это сработало:
- удалить Hangfire из запуска (я создавал свою работу там)
- удалена база данных hangfire
- перезапустить сервер
Я буду исследовать дальше позже, но метод, который я вызвал с помощью hangfire, получает DBContext, и это возможная причина.