Multi-assíncrono no Entity Framework 6?

87

Este é o meu código:

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

Mas quando chamei a função do controlador. Mostrou erro

Uma segunda operação foi iniciada neste contexto antes da conclusão de uma operação assíncrona anterior. Use 'await' para garantir que todas as operações assíncronas foram concluídas antes de chamar outro método neste contexto. Nenhum membro de instância tem garantia de thread-safe.

Por favor me ajude a resolver este problema.

Um Hv
fonte
Eu tenho 2 tarefas. Se eu executar cada tarefa. é sucesso. mas se eu executar como meu código acima. É um erro
An Hv

Respostas:

119

A exceção explica claramente que há apenas uma operação assíncrona permitida por contexto por vez.

Portanto, você precisa fazer awaitum de cada vez, conforme a mensagem de erro sugere:

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

Ou você pode usar vários contextos:

var banner = context1.Banners.ToListAsync();
var newsGroup = context2.NewsGroups.ToListAsync();
await Task.WhenAll(banner, newsGroup);
Stephen Cleary
fonte
34
Só uma observação, se você tem uma variável Lazy que usa o contexto na consulta mesmo com o await ela vai lançar o mesmo erro, é só pegar a propriedade antes da consulta, foi chato descobrir isso.
Pedro.The.Kid
7
@ Pedro.The.Kid: Como regra geral, não use o carregamento lento com acesso assíncrono ao banco de dados. O carregamento lento é sempre síncrono, então é muito melhor usar Incluir ou consultas separadas para os dados adicionais.
Stephen Cleary
1
Existe algum motivo específico pelo qual você precisa de um contexto por consulta assíncrona? Eu sinto que isso se torna um fator limitante.
Zapnologica de
1
@Zapnologica: É assim que o ES6 foi projetado. Cada contexto só pode lidar com uma consulta por vez . Portanto, se você terminar uma consulta antes do início da próxima, precisará apenas de um contexto. Só é um problema se você quiser fazer várias consultas ao mesmo tempo.
Stephen Cleary
@StephenCleary, estou tendo dificuldade em encontrar essa consulta, pois não há nada imediatamente antes da exceção. Existe uma maneira de encontrarmos o que está sendo executado atualmente? Obrigado
Fabio Milheiro
3

Se você usar o Unity para injeção de dependência com, por exemplo, padrão de repositório, você receberá o seguinte erro usando dois ou mais contextos com criar / atualizar / excluir:

O relacionamento entre os dois objetos não pode ser definido porque eles estão anexados a diferentes objetos ObjectContext.

Isso pode ser resolvido usando PerRequestLifetimeManager . Mais informações aqui:

C # EF6 faz várias chamadas assíncronas para um contexto usando Unity - Asp.Net Web Api

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