Curso Entity Framework - Atualizando um grafo de entidade usando o DBContext no modo desconectado - XXIII


  Nesta aula vamos mostrar como atualizar um grafo de entidades (um conjunto de entidades ou objetos) no cenário desconectado usando o DBContext. (aula anterior)

Chegou o Curso ASP .NET MVC 5 Vídeo Aulas (C#)

Clique e Confira

Atualizar um grafo de entidades com todas as novas entidades é uma tarefa complexa no cenário desconectado.

O problema na atualização de um grafo de entidades no cenário desconectado é que o contexto não conhece qual operação foi realizada do lado do cliente.

Na figura abaixo temos a representação desse fato onde o contexto não conhece o estado de cada entidade após uma operação ter sido realizada no cliente :

Precisamos identificar o estado de cada entidade no grafo de entidades antes de chamar o método SaveChanges().

Existem diferentes padrões para identificar o estado de uma entidade que precisamos considerar na concepção da camada de dados do Entity Framework.

Padrões para identificar o estado de uma entidade no cenário desconectado

Existem diversas formas de identificar o estado de uma entidade em um cenário desconectado. Dentre elas citamos:

  1. Usar a propriedade Primarykey (Id) de uma entidade

  2. Usando a propriedade state no conjunto de entidades (entity set)

Nota:  Você pode usar o seu próprio método para identificar o estado da entidade baseado na sua arquitetura.

1- Usando a propriedade Id (primary Key) de uma entidade

Você pode usar a chave primária - PrimaryKey (Id) de cada entidade para determina o seu estado. Porém, você tem que decidir qual das seguintes regras de arquitetura vai usar:

  1. Cada tipo de entidade deve possuir uma propriedade Id (chave primária)

  2. O valor padrão da propriedade Id deve ser 0

A seguir temos a figura que mostra como usar a propriedade Id para verificar o estado da entidades no cenário desconectado:

No cenário desconectado, o Contexto 2 não conhece o estado de cada entidade. Ele tem que determinar o estado da entidade padrão usando a propriedade PadraoId e o estado do Professor usando a propriedade ProfessorId.

Se os valores de PadraoId e ProfessorId forem iguais a zero, isso significa que elas são uma nova entidade e se o valor não for zero então significa que as entidade foram modificadas.

Na figura temos que Padrao, Professor 1 e Professor 2 possui um valor diferente de zero para a propriedade Id de forma que eles são marcados como Modified e Professor 3 possui o valor zero para o Id e assim ele é marcado como Added.

A seguir veremos o código que representa essa operação.

Atualizando um grafo de entidades aluno usando o Id

Vamos usar a solução criada na aula 22 - Entity Framework - Adicionando um grafo de entidade usando o DBContext no modo desconectado.

Abra a solução e no arquivo Program.cs e inclua o código abaixo neste arquivo:

 static void Atualizando_GrafoEntidades()
  {
            Padrao PadraoDesconectado = null;
            using (var contexto = new EscolaDBEntities())
            {
                //
                contexto.Configuration.ProxyCreationEnabled = false;
                //
                PadraoDesconectado = contexto.Padraos.Where(s => s.PadraoId == 58).Include(s => s.Professores).FirstOrDefault<Padrao>();
            }
            // Atualiza a entidade Padrao no modo desconectado
            PadraoDesconectado.PadraoNome = "Nome do Padrão editado e alterado";
            // Atualiza a coleção Professores editando o primeiro o professor e depois incluindo um novo professor
            PadraoDesconectado.Professores.ElementAt(0).ProfessorNome = "Nome do professor Alterado";
            PadraoDesconectado.Professores.Add(new Professor() { ProfessorNome = "Novo Professor", PadraoId = PadraoDesconectado.PadraoId });
            using (var novoContexto = new EscolaDBEntities())
            {
                //marca o padrao baseado no PadraoId
                novoContexto.Entry(PadraoDesconectado).State = PadraoDesconectado.PadraoId == 0 ? EntityState.Added : EntityState.Modified;
                //marca o Professor baseado no PadraodId
                foreach (Professor tchr in PadraoDesconectado.Professores)
                    novoContexto.Entry(tchr).State = tchr.ProfessorId == 0 ? EntityState.Added : EntityState.Modified;
                novoContexto.SaveChanges();
            }
 }

Vejamos quais as vantagens dessa abordagem:

E as desvantagens são:

2- Usando a propriedade State em cada entidade

Outra maneira de determinar o estado de uma entidade é ter uma propriedade State em cada tipo de entidade e definir o estado apropriado a partir do lado do cliente no modo desconectado. Dessa forma precisamos definir o estado da entidade como a propriedade State do objeto da entidade e chamar o método SaveChanges no novo Contexto.

Primeiro vamos criar uma interface IEntityObjectState com uma propriedade enum chamada EntityObjectState:
 
        public enum EntityObjectState
        {
            Added,
            Modified,
            Deleted,
            Unchanged
        }
        interface IEntityObjectState
        {
            EntityObjectState ObjectState { get; set; }
        }

A seguir vamos implementar a interface IEntityObjectSate em cada entidade. Abaixo vemos um exemplo para as entidades Padrao e Professor :
 
       public partial class Padrao : IEntityObjectState
        {
            public Padrao()
            {
                this.Alunos = new HashSet<Aluno>();
                this.Professores = new HashSet<Professor>();
            }
            public int PadraoId { get; set; }
            public string PadraoNome { get; set; }
            public string Descricao { get; set; }
            public virtual ICollection<Aluno> Alunos { get; set; }
            public virtual ICollection<Professor> Professores { get; set; }
            [NotMapped]
            public EntityObjectState ObjectState
            {
                get;
                set;
            }
        }
        public partial class Professor : IEntityObjectState
        {
            public Professor()
            {
                this.Cursos = new HashSet<Curso>();
            }
            public int ProfessorId { get; set; }
            public string ProfessorNome { get; set; }
            public Nullable<int> PadraoId { get; set; }
            public virtual ICollection<Curso> Cursos { get; set; }
            public virtual Padrao Padrao { get; set; }
            [NotMapped]
            public EntityObjectState ObjectState
            {
                get;
                set;
            }
        }

Defina a propriedade State no modo desconectado do lado do cliente e defina o estado da entidade como definido por ObjectState antes de chamar SaveChanges :

 
        static void Atualizando_GrafoEntidades_2()
        {
            Professor professorExistente = null;
            using (var context = new EscolaDBEntities())
            {
                context.Configuration.ProxyCreationEnabled = false;
                professorExistente = context.Professores.FirstOrDefault<Professor>();
            }
            Padrao PadraoDesconectado = new Padrao() { PadraoNome = "New Standard", ObjectState = EntityObjectState.Added };          
            professorExistente.ObjectState = EntityObjectState.Modified;
            //adiciona um professor existente  ao Padrao
            PadraoDesconectado.Professores.Add(professorExistente);
            //adiciona um novo Padrao
            PadraoDesconectado.Professores.Add(new Professor() { ProfessorNome = "New teacher", PadraoId = PadraoDesconectado.PadraoId, ObjectState = EntityObjectState.Added });
            //
            using (var newContext = new EscolaDBEntities())
            {
                // verifica a propriedade ObjectState e marca o apropriedado EntityState 
                if (PadraoDesconectado.ObjectState == EntityObjectState.Added)
                    newContext.Entry(PadraoDesconectado).State = System.Data.Entity.EntityState.Added;
                else if (PadraoDesconectado.ObjectState == EntityObjectState.Modified)
                    newContext.Entry(PadraoDesconectado).State = System.Data.Entity.EntityState.Modified;
                else if (PadraoDesconectado.ObjectState == EntityObjectState.Deleted)
                    newContext.Entry(PadraoDesconectado).State = System.Data.Entity.EntityState.Deleted;
                else
                    newContext.Entry(PadraoDesconectado).State = System.Data.Entity.EntityState.Unchanged;
                //verifica a propriedade ObjectState de cada professor e marca o apropriedado EntityState 
                foreach (Professor tchr in PadraoDesconectado.Professores)
                {
                    if (tchr.ObjectState == EntityObjectState.Added)
                        newContext.Entry(tchr).State = System.Data.Entity.EntityState.Added;
                    else if (tchr.ObjectState == EntityObjectState.Modified)
                        newContext.Entry(tchr).State = System.Data.Entity.EntityState.Modified;
                    else if (tchr.ObjectState == EntityObjectState.Deleted)
                        newContext.Entry(tchr).State = System.Data.Entity.EntityState.Deleted;
                    else
                        newContext.Entry(tchr).State = System.Data.Entity.EntityState.Unchanged;
                }
                //salva as mudanças
                newContext.SaveChanges();
            }
      }

As vantagens dessa abordagem são:

  • Nenhum código ou processamento extra é preciso para determinar o estado da entidade;
  • Ocorre o tratamento dos estados Added, Modified, Deleted e Unchanged;
  • Não é preciso chama a atualização para entidades não alteradas (Unchanged);

Desvantagens:

  • Precisamos definir os estados apropriados de cada entidade no modo desconectado de forma tomando muito cuidado com esta operação;

Apresentando as duas abordagens avalie qual se ajusta melhor ao seu cenário e a utilize quando for preciso.

Na próxima aula veremos a concorrência no Entity Framework.
 

Veja os Destaques e novidades do SUPER DVD Visual Basic (sempre atualizado) : clique e confira !

Quer migrar para o VB .NET ?

Quer aprender C# ??

 

             Gostou ?   Compartilhe no Facebook   Compartilhe no Twitter
 

Referências:


José Carlos Macoratti