Multi-async dans Entity Framework 6?

87

Voici mon code:

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

Mais quand j'ai appelé la fonction du contrôleur. Il a montré une erreur

Une deuxième opération a démarré sur ce contexte avant la fin d'une opération asynchrone précédente. Utilisez 'await' pour vous assurer que toutes les opérations asynchrones sont terminées avant d'appeler une autre méthode sur ce contexte. Les membres d'instance ne sont pas garantis d'être thread-safe.

Aidez-moi à résoudre ce problème.

Un Hv
la source
J'ai 2 tâches. Si j'exécute chaque tâche. c'est le succès. mais si je cours comme mon code ci-dessus. C'est une erreur
An Hv

Réponses:

119

L'exception explique clairement qu'il n'y a qu'une seule opération asynchrone par contexte autorisée à la fois.

Donc, vous devez les utiliser awaitun à la fois comme le suggère le message d'erreur:

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

Ou vous pouvez utiliser plusieurs contextes:

var banner = context1.Banners.ToListAsync();
var newsGroup = context2.NewsGroups.ToListAsync();
await Task.WhenAll(banner, newsGroup);
Stephen Cleary
la source
34
juste une note, si vous avez une variable Lazy qui utilise le contexte dans la requête même avec l'attente, elle lancera la même erreur, récupérez simplement la propriété avant la requête, c'était pénible de le découvrir.
Pedro.The.Kid
7
@ Pedro.The.Kid: En règle générale, n'utilisez pas le chargement différé avec un accès asynchrone à la base de données. Le chargement différé est toujours synchrone, il est donc préférable d'utiliser Inclure ou des requêtes séparées pour les données supplémentaires.
Stephen Cleary
1
Existe-t-il une raison spécifique pour laquelle vous avez besoin d'un contexte par requête asynchrone? J'ai l'impression que cela devient un peu un facteur limitant.
Zapnologica
1
@Zapnologica: C'est juste la façon dont ES6 a été conçue. Chaque contexte ne peut gérer qu'une seule requête à la fois . Donc, si vous terminez une requête avant que la suivante ne commence, vous n'avez besoin que d'un seul contexte. Ce n'est un problème que si vous souhaitez effectuer plusieurs requêtes en même temps.
Stephen Cleary
@StephenCleary, j'ai du mal à trouver cette requête car il n'y a rien juste avant l'exception. Y a-t-il un moyen pour nous de trouver ce qui est actuellement exécuté? Merci
Fabio Milheiro
3

Si vous utilisez Unity pour l'injection de dépendances avec, par exemple, un modèle de référentiel, vous obtiendrez l'erreur suivante en utilisant au moins deux contextes avec create / update / delete:

La relation entre les deux objets ne peut pas être définie car ils sont attachés à des objets ObjectContext différents.

Cela peut être résolu en utilisant PerRequestLifetimeManager. Plus d'infos ici:

C # EF6 effectue plusieurs appels asynchrones vers un contexte à l'aide de Unity - Asp.Net Web Api

container.RegisterType<DbContext>(new PerRequestLifetimeManager());
container.RegisterType<ISupplierRepository, SupplierRepository>();
container.RegisterType<IContactRepository, ContactRepository>();
Ogglas
la source