¿Multi-async en Entity Framework 6?

87

Este es mi codigo:

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

Pero cuando llamé a la función desde controller. Mostró error

Una segunda operación comenzó en este contexto antes de que se completara una operación asincrónica anterior. Utilice 'await' para asegurarse de que las operaciones asincrónicas se hayan completado antes de llamar a otro método en este contexto. No se garantiza que ningún miembro de instancia sea seguro para subprocesos.

Por favor ayudame a resolver este problema.

An Hv
fuente
Tengo 2 tareas. Si ejecuto cada tarea. es el éxito. pero si ejecuto como mi código anterior. Es un error
An Hv

Respuestas:

119

La excepción explica claramente que solo se permite una operación asincrónica por contexto a la vez.

Por lo tanto, debe hacerlo de awaituno en uno, como sugiere el mensaje de error:

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

O puede utilizar varios contextos:

var banner = context1.Banners.ToListAsync();
var newsGroup = context2.NewsGroups.ToListAsync();
await Task.WhenAll(banner, newsGroup);
Stephen Cleary
fuente
34
solo una nota, si tiene una variable Lazy que usa el contexto en la consulta incluso con la espera, arrojará el mismo error, solo obtenga la propiedad antes de la consulta, fue un dolor descubrir esto.
Pedro.The.Kid
7
@ Pedro.The.Kid: Como regla general, no use la carga diferida con acceso asincrónico a la base de datos. La carga diferida siempre es sincrónica, por lo que es mucho mejor usar Incluir o consultas separadas para los datos adicionales.
Stephen Cleary
1
¿Hay alguna razón específica por la que necesite un contexto por consulta asíncrona? Siento que esto se convierte en un factor limitante.
Zapnologica
1
@Zapnologica: Así es como se diseñó ES6. Cada contexto solo puede manejar una consulta a la vez . Entonces, si finaliza una consulta antes de que comience la siguiente, solo necesitará un contexto. Solo es un problema si desea realizar varias consultas al mismo tiempo.
Stephen Cleary
@StephenCleary, estoy teniendo dificultades para encontrar esa consulta porque no hay nada inmediatamente antes de la excepción. ¿Hay alguna forma de encontrar lo que se está ejecutando actualmente? Gracias
Fabio Milheiro
3

Si usa Unity para la inyección de dependencias con, por ejemplo, un patrón de repositorio, obtendrá el siguiente error al usar dos o más contextos con crear / actualizar / eliminar:

La relación entre los dos objetos no se puede definir porque están adjuntos a diferentes objetos ObjectContext.

Esto se puede resolver usando PerRequestLifetimeManager. Más info aquí:

C # EF6 realiza múltiples llamadas asíncronas a un contexto usando Unity - Asp.Net Web Api

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