Entity Framework - Simultaneidade

Qualquer desenvolvedor de acesso a dados enfrenta dificuldade ao responder à pergunta sobre a simultaneidade de dados, “O que acontece se mais de uma pessoa estiver editando os mesmos dados ao mesmo tempo?”

  • Os mais afortunados entre nós lidam com regras de negócios que dizem "sem problemas, o último em vitórias".

  • Nesse caso, a simultaneidade não é um problema. Mais provavelmente, não é tão simples assim e não existe solução mágica para resolver todos os cenários de uma vez.

  • Por padrão, o Entity Framework seguirá o caminho de “último em vitórias”, o que significa que a atualização mais recente é aplicada mesmo se outra pessoa atualizou os dados entre a hora em que os dados foram recuperados e a hora em que os dados foram salvos.

Vamos dar um exemplo para entender melhor. O exemplo a seguir adiciona uma nova coluna VersionNo na tabela Course.

Vá para o designer e clique com o botão direito na janela do designer e selecione atualizar o modelo do banco de dados ...

Você verá que outra coluna foi adicionada na Entidade do curso.

Clique com o botão direito do mouse na coluna recém-criada VersionNo, selecione Propriedades e altere ConcurrencyMode para Fixed, conforme mostrado na imagem a seguir.

Com o ConcurrencyMode de Course.VersionNo definido como Fixo, sempre que um Curso for atualizado, o comando Atualizar procurará o Curso usando seu EntityKey e sua propriedade VersionNo.

Vamos dar uma olhada em um cenário simples. Dois usuários recuperam o mesmo curso ao mesmo tempo e o usuário 1 altera o título desse curso para Matemática e salva as alterações antes do usuário 2. Mais tarde, quando o usuário 2 altera o título daquele curso que foi recuperado antes do usuário 1 salvar suas alterações, naquele caso o usuário 2 obterá exceção de simultaneidade"User2: Optimistic Concurrency exception occured".

using System;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Linq;

namespace DatabaseFirstDemo {

   class Program {

      static void Main(string[] args) {

         Course c1 = null;
         Course c2 = null;

         //User 1 gets Course

         using (var context = new UniContextEntities()) {
            context.Configuration.ProxyCreationEnabled = false;
            c1 = context.Courses.Where(s ⇒ s.CourseID == 1).Single();
         }

         //User 2 also get the same Course

         using (var context = new UniContextEntities()) {
            context.Configuration.ProxyCreationEnabled = false;
            c2 = context.Courses.Where(s ⇒ s.CourseID == 1).Single();
         }

         //User 1 updates Course Title
         c1.Title = "Edited from user1";

         //User 2 updates Course Title
         c2.Title = "Edited from user2";

         //User 1 saves changes first

         using (var context = new UniContextEntities()) {

            try {
               context.Entry(c1).State = EntityState.Modified;
               context.SaveChanges();
            } catch (DbUpdateConcurrencyException ex) {
               Console.WriteLine("User1: Optimistic Concurrency exception occurred");
            }
         }

         //User 2 saves changes after User 1.
         //User 2 will get concurrency exection
         //because CreateOrModifiedDate is different in the database

         using (var context = new UniContextEntities()) {

            try {
               context.Entry(c2).State = EntityState.Modified;
               context.SaveChanges();
            } catch (DbUpdateConcurrencyException ex) {
               Console.WriteLine("User2: Optimistic Concurrency exception occurred");
            }
         }
      }
   }
}