Избегайте ошибки Entity Framework при одновременном выполнении нескольких задач в одном DbContext
у меня есть контроллер WebApi в проекте ядра Dotnet под управлением ядра Entity Framework с Sqlite.
этот код в действии occationally выдает ошибки:
var t1 = _dbContext.Awesome.FirstOrDefaultAsync(a => [...]);
var t2 = _dbContext.Bazinga.FirstOrDefaultAsync(b => [...]);
var r1 = await t1;
var r2 = await t2;
ошибки:
Microsoft.EntityFrameworkCore.Запрос.RelationalQueryCompilationContextfactory: Ошибка: Ошибка в базе данных при переборе результатов запрос. Система.ObjectDisposedException: Безопасный дескриптор имеет был закрыт
Microsoft.EntityFrameworkCore.Запрос.RelationalQueryCompilationContextfactory: Ошибка: Ошибка в базе данных при переборе результатов запрос. Система.InvalidOperationException: ExecuteReader может быть только вызывается, когда соединение открыто.
обе ошибки мне подсказывают, что что-то происходит с DbContext
, как преждевременное избавление (хотя и не ). The DbContext
вводится в конструктор контроллера с использованием сантехники dotnet Core "обычным способом", конфигурация, как показано ниже (от my Startup.cs
ConfigureServices
метод body):
services.AddDbContext<ApplicationContext>(options => options.UseSqlite(connectionString));
если я изменю ошибку, производящую код выше, на что-то вроде:
var r1 = await _dbContext.Awesome.FirstOrDefaultAsync(a => [...]);
var r2 = await _dbContext.Bazinga.FirstOrDefaultAsync(b => [...]);
... Я не видел упомянутых ошибок, следовательно, вывод о том, что выполнение нескольких задач одновременно на одном экземпляре my DbContext
(вводили как описано выше), что причина проблемы. Очевидно, это неожиданно.
вопросы:
- можете ли вы точно определить, почему ошибки происходят только иногда?
- знаете ли вы какой-либо простой способ избежать проблемы при одновременном выполнении параллельных задач на
DbContext
?
1 ответов
к сожалению вы не можете сделать это.
EF Core не поддерживает несколько параллельных операций, выполняемых на одном экземпляре контекста. Перед началом следующей операции всегда следует дождаться завершения операции. Обычно это делается с помощью ключевого слова await в каждой асинхронной операции.
Потокобезопасность
хотя безопасность потоков сделала бы асинхронность более полезной, это ортогональная функция. Неясно, что мы могли бы когда-либо реализовать поддержку для него в самом общем случае, учитывая, что EF взаимодействует с графом, состоящим из пользовательского кода для поддержания состояния, и нет простых способов гарантировать, что этот код также потокобезопасен.
на данный момент EF обнаружит, пытается ли разработчик выполнить две асинхронные операции одновременно и бросать.
A DbContext
поддерживает только один открытый чтения данных в любой момент времени. Если вы хотите выполнить несколько одновременных запросов к базе данных, вам понадобится несколько DbContext
экземплярах, по одному для каждого параллельного запроса.
Что касается того, почему ошибка возникает иногда, ее состояние гонки. Просто потому, что вы начинаете 2 задачи одно за другим (не дожидаясь) не гарантирует, что база данных нажмите одновременно. Иногда время выполнения выстраивается в линию, а в других случаях одна задача может закончиться правильно, когда начинается другая задача, поэтому нет конфликта.
Как избежать этого-не делайте этого, поскольку он не поддерживается. Дождитесь каждого вызова DbContext или используйте несколько экземпляров DbContext.
под запросом я подразумеваю любую операцию БД, включая SELECT, UPDATE, DELETE, INSERT, ALTER, вызов хранимой процедуры и т. д.