Partilhar via


Guardar dados

Embora a consulta permita que você leia dados do banco de dados, salvar dados significa adicionar novas entidades ao banco de dados, remover entidades ou modificar as propriedades de entidades existentes de alguma forma. O Entity Framework Core (EF Core) suporta duas abordagens fundamentais para salvar dados no banco de dados.

Abordagem 1: rastreio de alterações e SaveChanges

Em muitos cenários, seu programa precisa consultar alguns dados do banco de dados, executar alguma modificação nele e salvar essas modificações de volta; Isto é por vezes referido como uma "unidade de trabalho". Por exemplo, vamos supor que você tenha um conjunto de blogs e queira alterar a Url propriedade de um deles. No EF, isso geralmente é feito da seguinte maneira:

using (var context = new BloggingContext())
{
    var blog = await context.Blogs.SingleAsync(b => b.Url == "http://example.com");
    blog.Url = "http://example.com/blog";
    await context.SaveChangesAsync();
}

O código acima executa as seguintes etapas:

  1. Ele usa uma consulta LINQ regular para carregar uma entidade do banco de dados (consulte Dados de consulta). As consultas do EF são rastreadas por padrão, o que significa que o EF rastreia as entidades carregadas em seu controlador de alterações interno.
  2. A instância de entidade carregada é manipulada como de costume, atribuindo uma propriedade .NET. A EF não está envolvida nesta etapa.
  3. Finalmente, chama-se DbContext.SaveChanges(). Neste ponto, o EF deteta automaticamente quaisquer alterações comparando as entidades com um instantâneo a partir do momento em que foram carregadas. Todas as alterações detetadas são mantidas no banco de dados; ao usar um banco de dados relacional, isso geralmente envolve o envio, por exemplo, de um SQL UPDATE para atualizar as linhas relevantes.

Observe que o acima descrito é uma operação de atualização típica para dados existentes, mas princípios semelhantes são válidos para adicionar e remover entidades. Você interage com o rastreador de alterações do EF chamando DbSet<TEntity>.Add e Removefazendo com que as alterações sejam rastreadas. Em seguida, o EF aplica todas as alterações controladas ao banco de dados quando SaveChanges() é chamado (por exemplo, via SQL INSERT e DELETE ao usar um banco de dados relacional).

SaveChanges() oferece as seguintes vantagens:

  • Você não precisa escrever código para controlar quais entidades e propriedades foram alteradas - o EF faz isso automaticamente para você e apenas atualiza essas propriedades no banco de dados, melhorando o desempenho. Imagine se suas entidades carregadas estiverem vinculadas a um componente da interface do usuário, permitindo que os usuários alterem qualquer propriedade que desejarem; A EF elimina o fardo de descobrir quais entidades e propriedades foram realmente alteradas.
  • Salvar alterações no banco de dados às vezes pode ser complicado! Por exemplo, se você quiser adicionar um Blog e algumas Postagens para esse blog, talvez seja necessário buscar a chave gerada pelo banco de dados para o Blog inserido antes de poder inserir as Postagens (já que elas precisam se referir ao Blog). A EF faz tudo isso por você, tirando a complexidade.
  • O EF pode detetar problemas de simultaneidade, como quando um registo de base de dados foi modificado por outra pessoa entre a sua consulta e SaveChanges(). Mais detalhes estão disponíveis em Conflitos de simultaneidade.
  • Em bancos de dados que oferecem suporte a ele, SaveChanges() encapsula automaticamente várias alterações em uma transação, garantindo que seus dados permaneçam consistentes se ocorrer uma falha. Mais detalhes estão disponíveis em Transações.
  • SaveChanges() Também agrupa várias alterações em muitos casos, reduzindo significativamente o número de viagens de ida e volta do banco de dados e melhorando consideravelmente o desempenho. Mais detalhes estão disponíveis em Atualização eficiente.

Para obter mais informações e exemplos de código sobre o uso básico SaveChanges() , consulte Basic SaveChanges. Para obter mais informações sobre o controle de alterações do EF, consulte a Visão geral do controle de alterações.

Abordagem 2: ExecuteUpdate e ExecuteDelete ("atualização em massa")

Embora o controle de alterações e SaveChanges() sejam uma maneira poderosa de salvar alterações, têm, no entanto, certas desvantagens.

Primeiro, SaveChanges() requer que você consulte e acompanhe todas as entidades que você modificará ou excluirá. Se precisar, por exemplo, excluir todos os blogs com uma classificação abaixo de um determinado limite, deverá consultar, materializar e rastrear um número potencialmente grande de linhas, e fazer com que SaveChanges() gere uma instrução DELETE para cada uma delas. Os bancos de dados relacionais fornecem uma alternativa muito mais eficiente: um único DELETE comando pode ser enviado, especificando quais linhas excluir por meio de uma WHERE cláusula, mas o SaveChanges() modelo não permite gerar isso.

Para dar suporte a esse cenário de "atualização em massa", você pode usar ExecuteDelete da seguinte maneira:

context.Blogs.Where(b => b.Rating < 3).ExecuteDelete();

Isso permite que você expresse uma instrução SQL DELETE por meio de operadores LINQ regulares - semelhante a uma consulta LINQ regular - fazendo com que o seguinte SQL seja executado no banco de dados:

DELETE FROM [b]
FROM [Blogs] AS [b]
WHERE [b].[Rating] < 3

Isso é executado de forma muito eficiente no banco de dados, sem carregar nenhum dado do banco de dados ou envolver o rastreador de alterações do EF. Da mesma forma, ExecuteUpdate permite que você expresse uma instrução SQL UPDATE .

Mesmo que você não esteja alterando entidades em massa, talvez saiba exatamente quais propriedades de qual entidade deseja alterar. Usar a API de controle de alterações para executar a alteração pode ser excessivamente complexo, exigindo a criação de uma instância de entidade, rastreá-la via Attach, fazer suas alterações e, finalmente, chamar SaveChanges(). Para tais cenários, ExecuteUpdate e ExecuteDelete pode ser uma maneira consideravelmente mais simples de expressar a mesma operação.

Finalmente, tanto o rastreamento de alterações quanto o próprio SaveChanges() impõem uma certa sobrecarga durante o tempo de execução. Se estiver a desenvolver uma aplicação de alto desempenho, ExecuteUpdate e ExecuteDelete permitem evitar ambos os componentes e gerar eficientemente a instrução desejada.

No entanto, note que ExecuteUpdate e ExecuteDelete também têm certas limitações:

  • Esses métodos são executados imediatamente e, atualmente, não podem ser agrupados em lote com outras operações. Por outro lado, SaveChanges(), pode agrupar operações em lotes.
  • Como o controle de alterações não está envolvido, é sua responsabilidade saber exatamente quais entidades e propriedades precisam ser alteradas. Isso pode significar mais código manual e de baixo nível rastreando o que precisa ser alterado e o que não precisa.
  • Além disso, como o controle de alterações não está envolvido, esses métodos não aplicam automaticamente o Controle de Simultaneidade quando as alterações persistem. No entanto, você ainda pode adicionar explicitamente uma Where cláusula para implementar o controle de simultaneidade.
  • Atualmente, apenas a atualização e a exclusão são suportadas; A inserção deve ser feita via DbSet<TEntity>.Add e SaveChanges().

Para obter mais informações e exemplos de código, consulte ExecuteUpdate e ExecuteDelete.

Resumo

A seguir estão algumas diretrizes para quando usar qual abordagem. Observe que estas não são regras absolutas, mas fornecem regras básicas úteis:

  • Se você não sabe com antecedência quais mudanças ocorrerão, use SaveChanges, ele detetará automaticamente quais alterações precisam ser aplicadas. Exemplos de cenários:
    • "Quero carregar um Blog do banco de dados e exibir um formulário permitindo que o usuário o altere"
  • Se você precisar manipular um gráfico de objetos (ou seja, vários objetos interconectados), use SaveChanges; ele descobrirá a ordenação adequada das alterações e como ligar tudo junto.
    • "Quero atualizar um blog, alterando alguns dos seus posts e apagando outros"
  • Se você deseja alterar um número potencialmente grande de entidades com base em algum critério, use ExecuteUpdate e ExecuteDelete. Exemplos de cenários:
    • "Quero dar um aumento a todos os funcionários"
    • "Quero excluir todos os blogs cujo nome começa com X"
  • Se você já sabe exatamente quais entidades deseja modificar e como deseja alterá-las, use ExecuteUpdate e ExecuteDelete. Exemplos de cenários:
    • "Quero apagar o blog cujo nome é 'Foo'"
    • "Quero mudar o nome do blog com Id 5 para 'Bar'"