Мульти-асинхронность в Entity Framework 6?

87

Это мой код:

var banner = context.Banners.ToListAsync()
var newsGroup = context.NewsGroups.ToListAsync()
await Task.WhenAll(banner, newsGroup);

Но когда я вызвал функцию из контроллера. Это показало ошибку

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

Пожалуйста, помогите мне решить эту проблему.

Hv
источник
У меня 2 задачи. Если я запускаю каждую задачу. это успех. но если я буду работать как мой код выше. Это ошибка
An Hv

Ответы:

119

Исключение ясно объясняет, что одновременно разрешена только одна асинхронная операция для каждого контекста.

Итак, вы должны либо обращаться к awaitним по одному, как следует из сообщения об ошибке:

var banner = await context.Banners.ToListAsync();
var newsGroup = await context.NewsGroups.ToListAsync();

Или вы можете использовать несколько контекстов:

var banner = context1.Banners.ToListAsync();
var newsGroup = context2.NewsGroups.ToListAsync();
await Task.WhenAll(banner, newsGroup);
Стивен Клири
источник
34
просто примечание: если у вас есть переменная Lazy, которая использует контекст в запросе, даже с ожиданием, она выдаст ту же ошибку, просто получите свойство перед запросом, было больно это выяснить.
Pedro.The.Kid
7
@ Pedro.The.Kid: Как правило, не используйте ленивую загрузку с асинхронным доступом к БД. Ленивая загрузка всегда синхронна, поэтому для дополнительных данных лучше использовать Include или отдельные запросы.
Стивен Клири
1
Есть ли какая-то конкретная причина, по которой вам нужен контекст для асинхронного запроса? Я чувствую, что это становится довольно ограничивающим фактором.
Zapnologica
1
@Zapnologica: Именно так был разработан ES6. Каждый контекст может обрабатывать только один запрос за раз . Поэтому, если вы закончите один запрос до начала следующего, вам понадобится только один контекст. Проблема только в том, что вы хотите выполнять несколько запросов одновременно.
Стивен Клири
@StephenCleary, мне трудно найти этот запрос, поскольку у меня нет ничего непосредственно перед исключением. Есть ли у нас способ узнать, что выполняется в настоящее время? Спасибо
Фабио Мильейро
3

Если вы используете Unity для внедрения зависимостей, например, с шаблоном репозитория, вы получите следующую ошибку, используя два или более контекстов с create / update / delete:

Связь между двумя объектами не может быть определена, поскольку они прикреплены к разным объектам ObjectContext.

Это можно решить с помощью PerRequestLifetimeManager . Больше информации здесь:

C # EF6 выполняет несколько асинхронных вызовов одного контекста с помощью Unity - Asp.Net Web Api

container.RegisterType<DbContext>(new PerRequestLifetimeManager());
container.RegisterType<ISupplierRepository, SupplierRepository>();
container.RegisterType<IContactRepository, ContactRepository>();
Огглас
источник