EF Core - Apresentando Shadow Properties


Neste artigo vou apresentar o novo recurso da EF Core chamado de Shadow Properties ou propriedades de sombra.

As propriedades de sombra ou Shadow Properites no Entity Framework Core são propriedades que não se apresentam como parte das suas entidades, mas podem ser definidas para a entidade no modelo EF Core e podem ser incluídas no modelo e são mapeadas para colunas de banco de dados. O valor e o estado dessas propriedades é mantido somente no Change Tracker ou controlador de alterações.

As propriedades de sombra são úteis em vários cenários.

Elas podem ser usadas para estender um modelo onde você não tem acesso ao código-fonte das classes de entidade, e, também podem ser usadas nos casos em que você prefere que as definições de classe de suas entidades não incluam "artefatos relacionais", como colunas de chaves estrangeiras ou propriedades de metadados, como DataCreated ou LastUpdated, ou uma propriedade rowversion.

Podemos obter e alterar o valor de uma Shadow Properties através da API ChangeTracker:

Na linha de código abaixo estamos alterando o valor da shadow property LastUpdated usando a propriedade Entry do DbContext :

context.Entry(meuBlog).Property("LastUpdated").CurrentValue = DateTime.Now;

Podemos referenciar uma shadow property em uma consulta LINQ por meio do método estático EF.Property :

var blogs = context.Blogs.OrderBy(b => EF.Property<DateTime>(b, "LastUpdated"));

Podemos configurar as shadow properties usando a Fluent API no método OnModelCreating.

Exemplo prático

Vamos ver um exemplo prático de utilização deste recurso usando o seguinte cenário:

Temos uma aplicação que usa o modelo de domínio Contato definido com as seguintes propriedades :

public class Contato
{
    public int ContatoId { get; set; }
    public string Nome { get; set; }
    public string Email { get; set; } 
}

Vou definir uma shadow property chamada UltimaAtualizacao no model EF Core que não esta presente na minha entidade usando á propriedade Entry do DbContext, e, vou fazer isso no método OnModelCreating da classe de Contexto ContatoDbContext que irei criar no projeto.

Recursos usados:

Criando a solução e o projeto no VS Community

Abra o VS 2017 Community e clique em Visual C# -> .NET Core e escolha o template Console App(.NET Core) :

Informe o nome EFCore_ShadowProperties e clique em OK;

Agora vamos incluir as seguintes referências via Nuget em nosso projeto:

No menu Tools clique em Nuget Package Manager e a seguir em Manage Nuget Packages for Solution;

Clique em Browse e localize o pacote e a seguir marque o projeto e clique em Install.

   

Repita o procedimento acima para cada pacote.

Criando o modelo de entidades

Crie uma pasta chamada Models no projeto e a seguir crie a classe Contato conforme o código mostrado a seguir:

1- Contato

using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace EFCore_ShadowProperties.Models
{
    [Table("Contatos")]
    public class Contato
    {
      public int ContatoId { get; set; }
      public string Nome { get; set; }
      public string Email { get; set; } 
    }
}

Na pasta Models crie a classe de contexto chamada ContatoDbContext que herda de DbContext e onde vamos definir a shadow property no método OnModelCreating :

5- ContatoDbContext

using Microsoft.EntityFrameworkCore;
using System;
namespace EFCore_ShadowProperties.Models
{
    public class ContatoDbContext : DbContext
    {
        public DbSet<Contato> Contatos { get; set; }
        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder.UseSqlServer(@"Data Source=Macoratti;Initial Catalog=TesteDB;Integrated Security=True");
        }
    
        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
             modelBuilder.Entity<Contato>().Property<DateTime>("UltimaAtualizacao");
         } 
    }
}

Nesta classe ContatoDbContext definimos a propriedade Contatos do tipo DbSet que vai mapear a entidade Contato para a tabela Contatos.

Para mapear a shadow property usamos a linha de código no método OnModelCreating():

modelBuilder.Entity<Contato>().Property<DateTime>("UltimaAtualizacao");

A versão do método Property que usa uma string e o tipo de dados da propriedade são especificados como um parâmetro de tipo. Uma vez que a shadow property foi declarada, ela pode ser configurada depois usando a Fluent API como qualquer outra propriedade do modelo.

Criando a tabela Contatos com a shadow property via Migrations

A propriedade shadow será incluída nas migrações (migrations), resultando em uma coluna chamada  "UltimaAtualizacao"  sendo adicionada na tabela Contatos.

Após instalar o pacote Microsoft.EntityFrameworkCore.Tools no projeto via Nuget para habilitar o Migrations:

Basta dar os comandos para iniciar o migrations e depois atualizar o banco de dados criando a tabela Contatos:

Consultando o SQL Server via SQL Server Management Studio vemos a tabela Contatos criada com a coluna UltimaAtualizacao incluída:

E estamos conversados...

(Disse Jesus) "Na verdade, na verdade vos digo que quem ouve a minha palavra, e crê naquele que me enviou, tem a vida eterna, e não entrará em condenação, mas passou da morte para a vida."
João 5:24


Referências:


José Carlos Macoratti