Entity Framework Core 1

Anexar Entidades em Cascata

Sempre foi possível “anexar” entidades a um contexto Entity Framework diferente daquele que as carregou. Por exemplo, entidades devolvidas por um web service (saber se um web service deve ou não devolver entidades é uma questão que não será discutida aqui) podem ser posteriormente anexadas a um contexto a residir num servidor diferente e serem tratadas como originarias desse contexto. A novidade introduzida na nova versão consiste em poder definir, para cada entidade relacionada com a entidade a anexar, qual o seu estado, do ponto de vista do novo contexto. Vejamos o que acontecia se anexássemos uma entidade com uma colecção de outras entidades associadas:

BlogContext ctx = /* ... */;
Blog blog = /* ... */;
ctx.Entry(blog).State = EntityState.Unchanged;
Código 12: Alteração do estado de uma entidade e todos os seus descendentes

Todos os elementos Post da colecção Posts da instância da classe Blog seriam, assim, marcados como não modificados. Imaginemos agora que possuíamos um grafo muito complexo onde, para cada entidade nele presente pretendíamos especificar o seu estado. Para esse cenário, foi criado o API TrackGraph:

BlogContext ctx = /* ... */;
Blog blog = /* ... */;
ctx.ChangeTracker.TrackGraph(blog, (node) =>
{
   if (node.Entry.Entity is Post)
   {
      //marcar o post como inalterado
      node.Entry.State = EntityState.Unchanged;
      //se a data do post for anterior a hoje
      if (((Post) node.Entry.Entity).Timestamp.Date < DateTime.Today)
      {
         //colocar uma indicação que será partilhada por todos os filhos
         node.NodeState = true;
      }
   }
   else if (node.Entry.Entity is Tag)
   {
      //usa a indicação colocada anteriormente
      if (node.NodeState == true)
      {
         node.Entry.State = EntityState.Deleted;
      }
      else
      {
         node.Entry.State = EntityState.Unchanged;
      }
   }
});
Código 13: Utilização do TrackGraph

Ou seja, o TrackGraph sabe como percorrer todas as relações a partir de uma entidade raiz e permite que adicionemos a nossa lógica para definição dos estados encontrados.

Geração de Entidades a Partir da Base de Dados

A Entity Framework possibilita a geração de entidades a partir da base de dados (claro está, apenas para bases de dados relacionais), sem necessidade do Visual Studio. Para tal, é necessário ter presente o fornecedor de acesso pretendido (p.ex., Microsoft.EntityFrameworkCore.SqlServer) e também a sua versão “design”, a qual contém a funcionalidade para geração de entidades (Microsoft.EntityFrameworkCore.SqlServer.Design). A sua utilização é simples:

dotnet ef dbcontext scaffold "Data Source=.\SQLEXPRESS; Initial Catalog=Blog; Integrated Security=SSPI" "Microsoft.EntityFrameworkCore.SqlServer"
Código 14: Geração de entidades a partir da base de dados

Claro está, este exemplo assume um servidor de base de dados SQL Server Express local com o nome SQLEXPRESS, uma base de dados chamada Blog e autenticação integrada do Windows. O leitor deverá alterar estes dados de acordo com o seu cenário concreto.

Outras Funcionalidades

Importa também referir que a nova Entity Framework possibilita também, na senda das versões anteriores, uma elevada extensibilidade: grande parte dos seus componentes pode ser trocada por outros. É possível, nomeadamente, injectar fornecedores de log, de geração de SQL, e muitos outros. Este tópico é vasto, pelo que fica apenas um exemplo de configuração de log para a consola:

public class ConsoleLoggerFactory : ILoggerFactory
{
   public void AddProvider(ILoggerProvider provider)  { }
   public void Dispose() { }
   public ILogger CreateLogger(string categoryName)
   {
      //fazer log de tudo para a consola
      return new ConsoleLogger(categoryName, (facility, level) => true, true);
   }
}

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
   optionsBuilder.UseLoggerFactory(new ConsoleLoggerFactory());
   optionsBuilder.UseSqlServer(@"Data Source=.\SQLEXPRESS; Integrated Security=SSPI; Initial Catalog=Blogs;")
   base.OnConfiguring(optionsBuilder);
}
Código 15: Configuração do fornecedor de log

Funcionalidades Ainda Não Suportadas

Nem tudo, no entanto, é positivo. Para não atrasar ainda mais a data de lançamento (já bastante atrasada), a versão 1.0 não inclui um número de funcionalidades que se encontravam nas versões anteriores:

  • Estratégias de mapeamento de heranças: apenas Table Per Type Hierarchy / Single Table Inheritance é suportada, não Table Per Type / Class Table Inheritance nem Table Per Concrete Type / Concrete Table Inheritance;
  • Carregamento implícito (lazy loading) e explícito (explicit loading) não são suportados; é necessário indicar, aquando da execução de uma query LINQ as entidades a trazer, por meio de chamadas a Include;
  • Relações muitos-para-muitos: podem ser emulados recorrendo a duas relações um-para-muitos;
  • Tipos complexos (complex types) também não existem na nova versão;
  • Mapeamento de inserções, alterações e apagamentos por procedimentos armazenados (stored procedures);
  • Agrupamentos (GROUP BY) na base de dados, ao invés de em memória;
  • A capacidade de associar entidades a vistas;
  • Estratégias para tentar re-executar comandos aquando de perda de ligação também não existirão;
  • A possibilidade de adicionar convenções personalizadas;
  • Intercepção de queries e comandos SQL;
  • Filtrar colecções de entidades a carregar;
  • Conversões de tipos de dados, por exemplo, de String para XML;
  • Como foi dito no início, todo o suporte a NoSQL não foi ainda incluído nesta primeira versão.

Funcionalidades Removidas

Foram removidas as seguintes funcionalidades, a título definitivo:

  • Todos os APIs dependentes de ObjectContext (introduzido na versão 1.0 da Entity Framework) foram removidos. Isto significa que não existe mais Entity SQL ou os eventos SavingChanges e ObjectMaterialized, mas também entidades com estado auto-gerido (self-tracking entities);
  • O interface IDatabaseInitializer<T> e todas as suas implementações (CreateDatabaseIfNotExists, DropCreateDatabaseAlways, DropCreateDatabaseIfModelChanges); a alternativa passa por usar exclusivamente migrações; também deixa de ser possível a alimentação de registos iniciais (seed);
  • Deixam de existir migrações automáticas;
  • A validação de dados de acordo com o API ComponentModel.DataAnnotations deixou de ser efectuada;
  • A abordagem model first deixa de ser suportada, apenas database first ou code first.

Conclusão

A nova versão da Entity Framework não deverá ficar para a história por si, mas pelo que possibilita. Na verdade, é a própria Microsoft a admiti-lo: esta nova versão não é a recomendada para uso profissional, devendo essa escolha recair sobre a Entity Framework 6.x. De facto, são tantas as lacunas que quase parece impossível que o gigante do software tenha optado por a tornar disponível, com tanta pompa e circunstância. No entanto, se pensarmos no suporte a múltiplas plataformas e na possibilidade (futura…) de usar o mesmo API quer para fontes de dados relacionais quer para não relacionais (Azure Table Storage, Redis, outras), a coisa muda de figura. Para sermos honestos, há algumas funcionalidades que merecem a nossa atenção desde já, mas, para uma utilização “a sério”, resta-nos esperar pela próxima versão. A curiosidade já aperta!

Referências

  1. https://github.com/aspnet/EntityFramework
  2. https://github.com/aspnet/EntityFramework/wiki/Roadmap
  3. http://ef.readthedocs.io/en/latest
  4. https://data.uservoice.com/forums/72025-entity-framework-feature-suggestions
  5. https://blogs.msdn.microsoft.com/dotnet/