Criando um Entity Framework global
DbContext
em uma aplicação web é muito ruim. O DbContext
classe não é thread-safe (e o mesmo vale para o ObjectContext
do Entity Framework v1 classe). Ele é construído em torno do conceito da unidade de trabalho
e isso significa que você o usa para operar um único caso de uso:portanto, para uma transação comercial. Destina-se a lidar com uma única solicitação. A exceção que você recebe acontece porque para cada solicitação você cria uma nova transação, mas tente usar esse mesmo
DbContext
. Você tem sorte que o DbContext
detecta isso e lança uma exceção, porque agora você descobriu que isso não funcionará. O
DbContext
contém um cache local de entidades em seu banco de dados. Ele permite que você faça várias alterações e, finalmente, envie essas alterações ao banco de dados. Ao usar um único DbContext
estático , com vários usuários chamando SaveChanges
nesse objeto, como é suposto saber o que exatamente deve ser confirmado e o que não deve? Como não sabe, salvará todos alterações, mas nesse ponto outra solicitação ainda pode estar fazendo alterações. Quando você tiver sorte, o EF ou seu banco de dados falhará, porque as entidades estão em um estado inválido. Se você não tiver sorte, as entidades que estão em um estado inválido serão salvas com sucesso no banco de dados e você poderá descobrir semanas depois que seus dados foram corrompidos.
A solução para o seu problema é criar pelo menos um
DbContext
por solicitação
. Embora em teoria você possa armazenar em cache um contexto de objeto na sessão do usuário, isso também é uma má ideia, porque nesse caso o DbContext
normalmente durará muito tempo e conterá dados obsoletos (porque seu cache interno não será atualizado automaticamente). Observe também que ter um
DbContext
por thread é tão ruim quanto ter uma única instância para o aplicativo web completo. O ASP.NET usa um pool de threads, o que significa que uma quantidade limitada de threads será criada durante a vida útil de um aplicativo da Web. Isso basicamente significa que aqueles DbContext
Nesse caso, as instâncias ainda viverão durante o tempo de vida do aplicativo, causando os mesmos problemas com a obsolescência dos dados. Você pode pensar que ter um
DbContext
por thread é realmente thread-safe, mas isso geralmente não é o caso, já que o ASP.NET tem um modelo assíncrono que permite finalizar as solicitações em um thread diferente de onde foi iniciado (e as versões mais recentes do MVC e da API da Web permitem até um número arbitrário de threads tratam de uma única solicitação em ordem sequencial). Isso significa que o encadeamento que iniciou uma solicitação e criou o ObjectContext
pode ficar disponível para processar outra solicitação muito antes da conclusão da solicitação inicial. No entanto, os objetos usados nessa solicitação (como uma página da Web, controlador ou qualquer classe de negócios) ainda podem fazer referência a esse DbContext
. Como a nova solicitação da Web é executada nesse mesmo thread, ela obterá o mesmo DbContext
instância como o que a solicitação antiga está usando. Isso novamente causa condições de corrida em seu aplicativo e causa os mesmos problemas de segurança de thread que um DbContext
global causas de instância.