Избегайте ошибки 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 (вводили как описано выше), что причина проблемы. Очевидно, это неожиданно.

вопросы:

  1. можете ли вы точно определить, почему ошибки происходят только иногда?
  2. знаете ли вы какой-либо простой способ избежать проблемы при одновременном выполнении параллельных задач на DbContext?

1 ответов


к сожалению вы не можете сделать это.

С основная документация EF

EF Core не поддерживает несколько параллельных операций, выполняемых на одном экземпляре контекста. Перед началом следующей операции всегда следует дождаться завершения операции. Обычно это делается с помощью ключевого слова await в каждой асинхронной операции.

и с документация EF 6

Потокобезопасность

хотя безопасность потоков сделала бы асинхронность более полезной, это ортогональная функция. Неясно, что мы могли бы когда-либо реализовать поддержку для него в самом общем случае, учитывая, что EF взаимодействует с графом, состоящим из пользовательского кода для поддержания состояния, и нет простых способов гарантировать, что этот код также потокобезопасен.

на данный момент EF обнаружит, пытается ли разработчик выполнить две асинхронные операции одновременно и бросать.


A DbContext поддерживает только один открытый чтения данных в любой момент времени. Если вы хотите выполнить несколько одновременных запросов к базе данных, вам понадобится несколько DbContext экземплярах, по одному для каждого параллельного запроса.

Что касается того, почему ошибка возникает иногда, ее состояние гонки. Просто потому, что вы начинаете 2 задачи одно за другим (не дожидаясь) не гарантирует, что база данных нажмите одновременно. Иногда время выполнения выстраивается в линию, а в других случаях одна задача может закончиться правильно, когда начинается другая задача, поэтому нет конфликта.

Как избежать этого-не делайте этого, поскольку он не поддерживается. Дождитесь каждого вызова DbContext или используйте несколько экземпляров DbContext.

под запросом я подразумеваю любую операцию БД, включая SELECT, UPDATE, DELETE, INSERT, ALTER, вызов хранимой процедуры и т. д.