У меня есть API.NET Core 1.1 с EF Core 1.1 и с использованием настройки Microsoft vanilla с использованием Injection Dependency для предоставления DbContext для моих сервисов. (Ссылка: https://docs.microsoft.com/en-us/aspnet/core/data/ef-mvc/intro#register-the-context-with-dependency-injection)
Теперь я рассматриваю распараллеливание базы данных как оптимизацию с использованием метода WhenAll
Поэтому вместо:
var result1 = await _dbContext.TableModel1.FirstOrDefaultAsync(x => x.SomeId == AnId);
var result2 = await _dbContext.TableModel2.FirstOrDefaultAsync(x => x.SomeOtherProp == AProp);
Я использую:
var repositoryTask1 = _dbContext.TableModel1.FirstOrDefaultAsync(x => x.SomeId == AnId);
var repositoryTask2 = _dbContext.TableModel2.FirstOrDefaultAsync(x => x.SomeOtherProp == AProp);
(var result1, var result2) = await (repositoryTask1, repositoryTask2 ).WhenAll();
Все это хорошо и хорошо, пока я не использую одну и ту же стратегию вне этих классов доступа к репозиторию БД и вызываю эти же методы с помощью WhenAll в своем контроллере через несколько служб:
var serviceTask1 = _service1.GetSomethingsFromDb(Id);
var serviceTask2 = _service2.GetSomeMoreThingsFromDb(Id);
(var dataForController1, var dataForController2) = await (serviceTask1, serviceTask2).WhenAll();
Теперь, когда я вызываю это из своего контроллера, я случайно получаю ошибки параллелизма, такие как:
System.InvalidOperationException: ExecuteReader требует открытого и доступного соединения. Состояние тока соединения закрыто.
Причина, по которой я верю, заключается в том, что иногда эти потоки пытаются получить доступ к тем же таблицам одновременно. Я знаю, что это по дизайну в EF Core, и если бы я хотел, чтобы я каждый раз создавал новый dbContext, но я пытаюсь посмотреть, есть ли способ обхода проблемы. Это, когда я нашел этот хороший пост Мехди Эль Гуддари: http://mehdi.me/ambient-dbcontext-in-ef6/
В этом он признает это ограничение:
внедренный DbContext не позволяет вам вводить многопотоковые или любые параллельные потоки выполнения в ваших сервисах.
И предлагает DbContextScope
решение проблемы с DbContextScope
.
Тем не менее, он предлагает оговорку даже с DbContextScope в том, что он не будет работать параллельно (что я пытаюсь сделать выше):
если вы попытаетесь запустить несколько параллельных задач в контексте DbContextScope (например, создав несколько потоков или несколько задач TPL), вы столкнетесь с большими проблемами. Это связано с тем, что окружающая среда DbContextScope будет проходить через все потоки, которые используются ваши параллельные задачи.
Его последний момент приводит меня к моему вопросу:
В общем, параллелизация доступа к базе данных в рамках одной бизнес-транзакции практически не имеет преимуществ и лишь добавляет значительную сложность. Любая параллельная операция, выполняемая в контексте бизнес-транзакции, не должна обращаться к базе данных.
Должен ли я не использовать WhenAll в этом случае в моих контроллерах и придерживаться его с помощью ожидания один за другим? Или это зависимость от DbContext, более фундаментальная проблема здесь, поэтому новый должен быть создан/поставлен каждый раз какой-то фабрикой?