Sqlserver
 sql >> Base de Dados >  >> RDS >> Sqlserver

.NET Entity Framework e transações


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.