EF Core - Fundamentos : Componentes


  Neste artigo vamos recordar conceitos básicos do Entity Framework Core apresentando os seus principais componentes.

O EF Core é resultado de uma evolução da ferramenta ORM chamada de Entity Framework que foi lançado em 2008 e incluido no .NET Framework 3.5 Service Pack 1.

Hoje temos a versão do Entity Framework para o .NET Framework e a versão para o .NET Core que atualmente é a versão 3.1.1. É desta versão que estamos tratando neste artigo.

A seguir veremos os principais componentes do EF Core.

Principais Componentes do EF Core

Existem cinco componentes pincipais que compõe o EF core:

  1. DbContext / DbContextOptions
  2. ChangeTracker
  3. DbSet/DbQuery
  4. Entities
  5. Database providers

Vejamos um resumo sobre cada um deles a seguir.

1- DbContext/DbContextOptions

O DbContext é o coração do EF Core. Representa uma sessão com o banco de dados e é o controlador central que contém instâncias das coleções DbSet<T> e DbQuery<T> e o ChangeTracker.

As classes DbContext derivadas são configuradas usando uma instância do DbContextOptions.

A classe DbContext

A classe DbContext não é usada diretamente, mas através de classes que herdam da classe DbContext. As entidades mapeadas para o banco de dados são adicionadas como DbSet<T> e propriedades DbQuery<T> na classe derivada.

O método OnModelCreating é usado para definir os mapeamentos entre as entidades e o banco de dados.

O método SaveChanges persiste todas as alterações no banco de dados em uma transação implícita.

A seguir temos algumas propriedades e métodos mais usados da classe DbContext:

a- Principais propriedades expostas por DbContext

Propriedade Definição
Database fornece acesso a informações e funcionalidades relacionadas ao banco de dados,incluindo execução de instruções SQL
Model Os metadados sobre a forma das entidades, os relacionamentos entre elas, e como elas são mapeadas para o banco de dados.
ChangeTracker Fornece acesso a informações e operações para instâncias de entidades que o contexto está rastreando
DbSet<T> Usado para consultar e salvar instâncias das entidades definidas. As consultas feitas usando LINQ contra as propriedades DbSet<T> são convertida em consultas SQL.
DbQuery<T> Usado para consultar dados do banco de dados usando fontes que não são tabelas, como Views

b- Principais métodos expostos por DbContext

Método Definição
Entry

Entry<Entity>

Fornece acesso a informações e operações de rastreamento alteradas (como alterações no EntityState) para a entidade. Também pode ser chamado em uma entidade não rastreada para alterar o estado para rastreado.
SaveChanges

SaveChangesAsync

Salva todas as alterações de entidade no banco de dados e retorna o número de
registros afetados
OnConfiguring Um builder usado para criar ou modificar opções para o contexto. Executa sempre que uma instância DbContext é criada. Nota: Prefira usar o DbContextOptions para configure o contexto em tempo de execução e use uma instância do IDesigntimeDbContextFactory em tempo de projeto.
OnModelCreating Chamado quando um modelo foi inicializado, mas antes de ser finalizado. Os métodos do Fluent API são colocados neste método para finalizar a forma do modelo.

A classe DbContextOptions

Esta classe configura uma instância de uma classe DbContext derivada e é injetado na classe DbContext derivada com injeção de construtor. As opções são criadas usando um DbContextOptionsBuilder, pois o DbContextOptions não se destina a ser construído diretamente em seu código.

2- ChangeTracker

O rastreador de alterações monitora as entidades nas propriedades DbSet<T> no DbContext derivado. Os itens que foram adicionados, excluídos ou alterados são relatados ao DbContext quando SaveChanges for executado para executar as instruções SQL corretas para dados persistentes.

O ChangeTracker usa o EntityState para rastrear o status das entidades nas propriedades DbSet<T>. Os diferentes estados de uma entidade estão listados a seguir:

EntityState Definição
Added A entidade está sendo rastreada, mas ainda não existe no banco de dados.
Deleted A entidade está sendo rastreada e é marcada para exclusão do banco de dados.
Detached A entidade não está sendo rastreada pelo contexto.
Modified A entry (entrada) está sendo rastreada e foi alterada
Unchanged A entidade está sendo rastreada, existe no banco de dados e não foi modificada.

3 - Os tipos de coleção DbSet<T> e DbQuery<T>

O DbSet<T> e o DbQuery<T> são coleções especializadas usadas pelo EF Core para manter instâncias de entidades que são mapeadas para o banco de dados. O DbSet<T> é usado para operações de leitura/gravação e o DbQuery <T> é usado para operações somente leitura.

O tipo de coleção DbSet<T>

Cada coleção de modelos que pode ser atualizada é representada pela propriedade de coleção especializada DbSet<T> na classe DbContext.

Cada propriedade DbSet<T> contém todos as entidades semelhantes rastreadas no contexto e expõe métodos para obter dados do banco de dados, bem como métodos para persistir dadaos de volta ao banco de dados.

A recuperação de dados é realizada usando consultas LINQ que são convertidas em SQL e depois executadas no banco de dados. Dados adicionados ou removidos das coleções, bem como os dados modificados, não são persistidos no banco de dados até que o método SaveChanges no DbContext derivado seja executado.

As entidades colocadas nas coleções DbSet<T> devem ter uma chave primária (simples ou complexa)
definida.

A seguir temos alguns dos métodos disponíveis no DbSet<T> mais usados:

Método DbSet<T> Definição
Add/AddRange Começa a rastrear a entidade/entidades no estado Added. Os itens serão adicionados quando SaveChanges for chamado. (*)
Find Realiza Pesquisas para a entidade no ChangeTracker por chave primária. Se não for encontrada, o armazenamento de dados é consultado para o objeto. (*)
Update/UpdateRange  Começa a rastrear a entidade/entidades no estado Modified. Os itens serão atualizados quando SaveChanges for chamado.(*)
Remove Inicia o rastreamento da entidade/entidades no estado deleted. Os itens serão removidos quando SaveChanges for chamado.(*)
Attach/AttachRange Começa a rastrear a entidade/entidades no estado Unchanged. Nenhuma operação será executada quando SaveChanges for chamado.(*)

(*) - Versões assíncronas também estão disponíveis. Todos os métodos acima podem ser chamados diretamente na classe derivada DbContext ou nas propriedades DbSet<t>.

O tipo de coleção DbQuery <T>

Este recurso foi adicionado no EF Core 2.1, o DbQuery<T> é usado para consultar diretamente o banco de dados usando fontes diferentes de tabelas, como views e procedimentos armazenados.

A restrição de exigir que uma chave primária é levantada ao usar um DbQuery<T>, o que torna essa coleção o
tipo ideal para situações somente leitura.

4- Entities

Entidades são objetos POCOs simples (Plain Old C# Objects) que são mapeados para o banco de dados através de convenções, atributos e/ou via código no método OnModelCreating.

Cada entidade é adicionada ao DbContext por meio das propriedades DbSet<T> ou DbQuery<T>, e, Entidades
estão relacionadas a outras entidades por meio de propriedades de navegação, que se tornam chaves estrangeiras
no modelo de banco de dados.

Classes herdadas e Classes Owned (EF Core 2.1) são combinadas em uma única tabela quando mapeada para o banco de dados. Isso é chamado de padrão de tabela por hierarquia.

Configuração de Entity

As entidades no EF Core são classes C# que são mapeadas para as tabelas do banco de dados. Os mapeamentos são definidos com convenções internas, atributos C# (referidos como anotações de dados) e código C# no método OnModelCreating. O código usado neste último é conhecido como Fluent API.

Convenções

Existem muitas convenções embutidas no EF Core que definem os mapeamentos entre as entidades e as tabelas.

Eles são baseadas em condições como nomes e tipos de dados, e reduzem a quantidade de configuração manual necessária. No entanto, existem muitos deles que devemos conhecer e isso pode causar problemas. Se nem todas as convenções forem entendidas, pode ser confusão e também erros.

Um exemplo de uma convenção diz respeito aos campos da chave primária. A convenção da chave primária
cria uma chave primária para uma tabela quando sua Entidade tem um campo chamado Id ou <NomeClasse>Id
(como ClienteId em uma classe chamada Cliente).

Para o SQL Server, se o tipo de dados for int ou GUID, os valores serão gerados pelo servidor quando um novo registro for adicionado. Cada provedor de banco de dados também possui suas próprias variações dessa convenção.

Embora as convenções possam ser úteis, quanto mais “molho secreto” um projeto tiver, maior será a oportunidade de haver problemas. Em vez de confiar apenas em convenções, uma prática comum é ser explícito ao definir as entidades usando as anotações de dados e/ou a Fluent API.

Anotações de Dados ou Data Annotations

As anotações de dados são aplicadas como atributos .NET nas definições das entidades e mapeiam explicitamente as entidades para as tabelas e propriedades para colunas e chaves (primárias e estrangeiras).

As anotações de dados ten precedência sobre as convenções e sobrepõem quaisquer conflitos. A  seguir etmos alguns das data annotations mais comuns usadas no EF Core:

Data Annotation Definição
Table Define o nome do schema e o nome da tabela para a entidade
Column Define o nome da coluna para propriedade model
Key Define a chave primária para o model. Os campos Key são implicitamente [required].
Required Declara a propriedade como não anulável (not nullable) no banco de dados
ForeignKey Declara a propriedade que é usada como chave estrangeira para a propriedade de navegação
InverseProperty Declara a propriedade de navegação no outro fim do relacionamento
MaxLength Especifica o comprimento máximo para a propriedade string
TimeStamp Declara o tipo como um rowversion no SQL Server e adiciona a verificação da concorrência para as operações do banco de dados envolvendo a entidade
DatabaseGenerated Especifica se o campo no banco de dados será gerado ou não.
NotMapped Exclui a propriedade ou classe do mapeamento para o banco de dados
DataType Fornece uma definição mais especifica do campo

Fluent API

A Fluent API configura as entidades do aplicativo através do código C#. Os métodos são exposto pela instância ModelBuilder disponível no método OnModelCreating do DbContext.

Este recurso é o mais poderoso dos métodos de configuração e sobrescreve quaisquer convenções de dados ou anotações de dados que estejam em conflito. Algumas das opções de configurações somente estão disponíveis  usando a API Fluent, como chaves e índices complexos.

Propriedades de navegação e chaves estrangeiras

As propriedades de navegação representam como as classes do modelo se relacionam e habilitam código para percorrer o modelo de objetos.

No lado do banco de dados, as propriedades de navegação são traduzidas em relacionamentos de chave estrangeira entre tabelas. Os relacionamentos um para um e um para muitos são suportados diretamente no EF Core. Relacionamentos muitos para muitos são suportados usando uma entidade de junção entre as duas tabelas.

Para criar um relacionamento um para muitos, a classe do lado um adiciona um List<T> do filho. Por outro lado, a classe adiciona uma propriedade do tipo pai, bem como uma propriedade do mesmo tipo que a chave primária dos pais.

5 - Provedores de banco de dados

O EF Core usa um modelo de provedor para permitir o uso com diferentes bancos de dados. Cada provedor deve
implementar a funcionalidade base, mas também pode adicionar funcionalidades específicas ao banco de dados.

A lista de provedores suportados (gratuitos e comerciais) cresce a cada lançamento. Os provedores de suporte atuais podem ser encontrados neste link :  https://docs.microsoft.com/en-us/ef/core/providers/

Vimos assim os principais componentes e suas principais características. Espera-se que um desenvolvedor conheça pelo menos os conceitos aqui apresentados para poder usar o EF Core nos projetos da plataforma .NET

Em outro artigo veremos outros recursos do EF Core.

"(Disse Jesus)Passará o céu e a terra, mas as minhas palavras não hão de passar."
Lucas 21:33

Referências:


José Carlos Macoratti