Partilhar via


Trabalhar com estados da entidade

Este tópico abordará como adicionar e anexar entidades a um contexto e como o Entity Framework processa estas durante o SaveChanges. O Entity Framework trata de acompanhar o estado das entidades enquanto estão ligadas a um contexto, mas em cenários desconectados ou N-Tier podes informar a EF em que estado as tuas entidades devem estar. As técnicas apresentadas neste tópico aplicam-se igualmente a modelos criados com o Code First e o EF Designer.

Estados das entidades e SaveChanges

Uma entidade pode estar num dos cinco estados, conforme definido pela enumeração EntityState. Estes estados são:

  • Acrescentado: a entidade está a ser rastreada pelo contexto, mas ainda não existe na base de dados
  • Inalterado: a entidade está a ser acompanhada pelo contexto e existe na base de dados, e os valores das suas propriedades não mudaram em relação aos valores da base de dados
  • Modificado: a entidade está a ser acompanhada pelo contexto e existe na base de dados, e alguns ou todos os seus valores de propriedade foram modificados
  • Eliminado: a entidade está a ser acompanhada pelo contexto e existe na base de dados, mas foi marcada para ser eliminada da base de dados na próxima vez que o SaveChanges for chamado.
  • Desligado: a entidade não está a ser rastreada pelo contexto

O SaveChanges faz coisas diferentes para entidades em diferentes estados:

  • As entidades inalteradas não são afetadas pelo SaveChanges. As atualizações não são enviadas para a base de dados para entidades no estado Inalterado.
  • As entidades adicionadas são inseridas na base de dados e depois tornam-se Inalteradas quando o SaveChanges regressa.
  • As entidades modificadas são atualizadas na base de dados e depois tornam-se Inalteradas quando o SaveChanges regressa.
  • As entidades eliminadas são eliminadas da base de dados e depois desligadas do contexto.

Os exemplos seguintes mostram formas pelas quais o estado de uma entidade ou de um grafo de entidades pode ser alterado.

Adicionar uma nova entidade ao contexto

Uma nova entidade pode ser adicionada ao contexto chamando o método Add no DbSet. Isto coloca a entidade no estado Adicionado, o que significa que será inserida na base de dados da próxima vez que o SaveChanges for chamado. Por exemplo:

using (var context = new BloggingContext())
{
    var blog = new Blog { Name = "ADO.NET Blog" };
    context.Blogs.Add(blog);
    context.SaveChanges();
}

Outra forma de adicionar uma nova entidade ao contexto é mudar o seu estado para Adicionado. Por exemplo:

using (var context = new BloggingContext())
{
    var blog = new Blog { Name = "ADO.NET Blog" };
    context.Entry(blog).State = EntityState.Added;
    context.SaveChanges();
}

Finalmente, podes adicionar uma nova entidade ao contexto ligando-a a outra entidade que já está a ser rastreada. Isto pode acontecer adicionando a nova entidade à propriedade de navegação da coleção de outra entidade ou definindo uma propriedade de navegação de referência de outra entidade para apontar para a nova entidade. Por exemplo:

using (var context = new BloggingContext())
{
    // Add a new User by setting a reference from a tracked Blog
    var blog = context.Blogs.Find(1);
    blog.Owner = new User { UserName = "johndoe1987" };

    // Add a new Post by adding to the collection of a tracked Blog
    blog.Posts.Add(new Post { Name = "How to Add Entities" });

    context.SaveChanges();
}

Note que, para todos estes exemplos, se a entidade adicionada tiver referências a outras entidades que ainda não foram rastreadas, essas novas entidades também serão adicionadas ao contexto e inseridas na base de dados na próxima vez que o SaveChanges for chamado.

Anexar uma entidade existente ao contexto

Se tiver uma entidade que sabe que já existe na base de dados mas que não está a ser rastreada pelo contexto, pode dizer ao contexto para rastrear a entidade usando o método Attach no DbSet. A entidade estará em estado Inalterado no contexto. Por exemplo:

var existingBlog = new Blog { BlogId = 1, Name = "ADO.NET Blog" };

using (var context = new BloggingContext())
{
    context.Blogs.Attach(existingBlog);

    // Do some more work...  

    context.SaveChanges();
}

Note que não serão feitas alterações à base de dados se o SaveChanges for chamado sem qualquer outra manipulação da entidade associada. Isto acontece porque a entidade está no estado Inalterado.

Outra forma de associar uma entidade existente ao contexto é mudar o seu estado para Inalterado. Por exemplo:

var existingBlog = new Blog { BlogId = 1, Name = "ADO.NET Blog" };

using (var context = new BloggingContext())
{
    context.Entry(existingBlog).State = EntityState.Unchanged;

    // Do some more work...  

    context.SaveChanges();
}

Note que, para ambos os exemplos, se a entidade anexada tiver referências a outras entidades que ainda não foram rastreadas, então essas novas entidades também serão ligadas ao contexto no estado Inalterado.

Anexar uma entidade existente mas modificada ao contexto

Se tiver uma entidade que sabe que já existe na base de dados, mas à qual podem ter sido feitas alterações, pode indicar ao contexto para anexar a entidade e definir o seu estado para Modificado. Por exemplo:

var existingBlog = new Blog { BlogId = 1, Name = "ADO.NET Blog" };

using (var context = new BloggingContext())
{
    context.Entry(existingBlog).State = EntityState.Modified;

    // Do some more work...  

    context.SaveChanges();
}

Quando mudares o estado para Modificado, todas as propriedades da entidade serão marcadas como modificadas e todos os valores das propriedades serão enviados para a base de dados quando o SaveChanges for chamado.

Note que, se a entidade anexada tiver referências a outras entidades que ainda não foram rastreadas, então essas novas entidades serão ligadas ao contexto no estado Inalterado — não serão automaticamente tornadas Modificadas. Se tiver várias entidades que precisam de ser marcadas como Modificadas, deve definir o estado de cada uma destas entidades individualmente.

Alterar o estado de uma entidade rastreada

Pode alterar o estado de uma entidade que já está a ser rastreada definindo a propriedade Estado na respetiva entrada. Por exemplo:

var existingBlog = new Blog { BlogId = 1, Name = "ADO.NET Blog" };

using (var context = new BloggingContext())
{
    context.Blogs.Attach(existingBlog);
    context.Entry(existingBlog).State = EntityState.Unchanged;

    // Do some more work...  

    context.SaveChanges();
}

Note que chamar Adicionar ou Anexar para uma entidade já rastreada também pode ser usado para alterar o estado da entidade. Por exemplo, ao utilizar o comando Anexar para uma entidade que está atualmente no estado Adicionado, o seu estado mudará para Inalterado.

Padrão de inserção ou atualização

Um padrão comum para algumas aplicações é adicionar uma entidade como nova (resultando numa inserção de base de dados) ou anexar uma entidade como existente e marcá-la como modificada (resultando numa atualização da base de dados) dependendo do valor da chave primária. Por exemplo, ao usar chaves primárias inteiras geradas por base de dados, é comum tratar uma entidade com chave zero como nova e uma entidade com chave não nula como existente. Este padrão pode ser alcançado definindo o estado da entidade com base numa verificação do valor da chave primária. Por exemplo:

public void InsertOrUpdate(Blog blog)
{
    using (var context = new BloggingContext())
    {
        context.Entry(blog).State = blog.BlogId == 0 ?
                                   EntityState.Added :
                                   EntityState.Modified;

        context.SaveChanges();
    }
}

Note que, ao alterar o estado para Modificado, todas as propriedades da entidade serão marcadas como modificadas e todos os valores das propriedades serão enviados para a base de dados quando o SaveChanges for chamado.