Pontos de dados

Olhando para o Entity Framework 7

Julie Lerman

Julie LermanDesenvolvimento da próxima versão do Entity Framework está bem encaminhado. Eu tenho o meu primeiro vislumbre sobre o que a equipe EF estava trabalhando no TechEd North America 2014, quando o Gerente de Programa, Rowan Miller falou sobre os objetivos para o Entity Framework 7 (EF7) e demonstrou alguns dos primeiros pedaços.

Isso foi há cinco meses, conforme eu estou escrevendo esta coluna, e embora o EF7 ainda seja um alfa precoce, ele já percorreu um longo caminho. Nesta coluna eu quero deixá-lo consciente do que o EF7 trará para os desenvolvedores, as motivações por trás das decisões que estão sendo tomadas sobre EF7, e o que esta versão significa para os aplicativos existentes que usam EF6 ou versão anterior. Eu também vou te fornecer uma espiada da parte do código que será semelhante.

Código aberto, mas agora no GitHub

A primeira coisa a saber sobre EF7 é que, como o EF6, é de código aberto. Mas ao invés de ser desenvolvido no CodePlex, o EF7 está no GitHub, junto com o resto da versão seguinte do ASP.NET. A URL para o desenvolvimento do EF7 é github.com/aspnet/EntityFramework. Assim como no EF6, você será capaz de ver os detalhes do EF7 conforme ele evolui. Você pode explorar a fonte, bem como o seu progresso através de ramificações e confirmações, acompanhar as discussões, levantar questões, bifurcar a fonte e enviar solicitações por pull para a equipe examinar e potencialmente confirmar a base de código.

O EF6 não vai embora tão cedo

Não se preocupe - você não será forçado a se mudar para o EF7. Pense novamente nos DataSets ADO.NET e DataReaders. Muito parecido com ASP.NET Web Forms, que ainda são suportados e até mesmo se beneficiam de ajustes ocasionais, o ADO.NET ainda faz parte do Microsoft .NET Framework, apesar do EF ter sido a tecnologia de acesso de dados primários para .NET por muitos anos. Não aconteceu muita coisa para melhorar essas tecnologias, mas eles ainda estão lá, e ainda suportam muitos códigos herdados (inclusive o meu). Uma das grandes vantagens que o EF6 tem sobre as outras tecnologias é que é de código aberto, por isso mesmo que a equipe da Microsoft não vai fazer grandes investimentos no EF6, a comunidade ainda será capaz. E a equipe EF está comprometida com o EF6. Eles vão continuar a fazer ajustes, inspecionando as solicitações por pull e a atualização do EF6 de perto. Mesmo que eles fossem de diâmetro completo no EF7 para uma boa parte de 2014, o EF6 foi atualizado. A versão 6.1.0 foi lançada em fevereiro de 2014; a versão 6.1.1. em junho de 2014; e enquanto eu estou escrevendo este artigo, a versão 6.1.2. está na fase beta, para ser lançada em breve. Eu inicialmente estava preocupada, mas não estou mais, sobre ser capaz de manter tais aplicativos funcionando. Os únicos que me preocupam são os primeiros aplicativos que usou o EF com o .NET Framework 3.5, ObjectContext e mais. Mas se você ainda não atualizou estes aplicativos para alavancar todas as grandes melhorias para o EF ao longo dos anos, você pode não estar preocupado o suficiente com o EF7, de qualquer forma. Você também pode encontrar todos os pacotes anteriores do EF no NuGet, tudo de volta para o EF 4.1.10311.

EF7: A lista curta

Aqui está a exibição de alto nível do que é emocionante no EF7:

  • Suporte para armazenamentos de dados não-relacionais e até mesmo dados na memória para teste.
  • Suporte para máquinas e dispositivos que não usam o .NET Framework completo. Isso significa que você pode usar o EF7 nos aplicativos do Windows Phone e Windows Store, assim como nas máquinas do Linux e Macintosh que estão executando o Mono.
  • Suporte para vários recursos que os desenvolvedores solicitaram, mas não poderiam alcançar com a base de código existente.
  • Suporte contínuo para aplicativos que usam o .NET Framework completo, como o Windows Presentation Foundation e outros aplicativos do cliente.
  • O EF7 será distribuído da mesma forma que o ASP.NET 5 e pode ser usado com os aplicativos do ASP.NET 5.

Superfície da codificação familiar, nova base de código

Cada versão do EF desenvolveu a estrutura, adicionando novas capacidades e desempenho de ajuste fino e APIs. Conforme eu já escrevi antes nesta coluna, bem como em um artigo de visão geral na edição de dezembro de 2013, o "Entity Framework 6: The Ninja Edition” (bit.ly/1cwjyCD), a versão mais recente trouxe o EF a um novo nível, dando à estrutura muitos recursos que os usuários vêm pedido ao longo do caminho, como execução do banco de dados assíncrono, tocar no pipeline de pesquisa, personalizar as convenções do Code First e muito mais. Eu exercito muito mais nestes recursos no meu curso Pluralsight, "Entity Framework 6, Ninja Edition: What’s New in EF6” (bit.ly/PS-EF6).

Existem ainda mais recursos que os desenvolvedores estão procurando para o EF que a Microsoft estava pronto para implementar, mas a base do código de mais de 10 anos do EF é criada - com uma dependência contínua no ObjectContext e padrões de codificação menos flexível - evitando que a equipe chegue ao próximo nível de capacidade. Uma decisão difícil - que certamente muitos de você enfrentou com seu próprio software herdado - foi tomada para recriar o Entity Framework do zero.

O EF7 não é criação de uma nova estrutura para acesso aos dados. Ao invés disso, é criação de uma base nova, mais sustentável em que para suportar não apenas os recursos e fluxo de trabalho, você dependia durante anos do EF, mas também daquele que permitirá muito mais. A equipe lutou como se este fosse o próximo EF ou a nova tecnologia de acesso aos dados. A um determinado ponto, eu ainda questionei se deveria ser "EF Light". Mas a funcionalidade principal do EF ainda está lá e após muita consideração, eu concordo que faz sentido pensar neste como a próxima versão do Entity Framework. Você pode ler mais sobre isso na publicação do bog da equipe, "EF7 - v1 ou v7"? (bit.ly/1EFEdRH).

Mudando algum peso herdado, mantendo as partes boas

No entanto, existem também notícias sobre o EF7 que são preocupantes para alguns desenvolvedores. Enquanto as classes EF mais comuns, padrões e fluxos de trabalho permanecerão intactos, alguns dos membros menos usados serão deixados para trás. Mas não entre em pânico; eu falarei sobre isso em alguns momentos.

Foi uma meta fundamental permitir que os desenvolvedores continuem a usar os padrões familiares e até mesmo serem capazes de transportar boa quantidade de código existente para o EF7. Você ainda usa DbContext, DbSet, consultas LINQ, SaveChanges e muitos dos meios de interação que fizeram parte do EF por muito tempo.

Aqui está uma classe DbContext que eu defini no EF7:

public class BreweryContext : DbContext {
  public DbSet<Brewery> Breweries { get; set; }
  public DbSet<Beer> Beers { get; set; }
}

E aqui está uma atualização simples no EF7 que é a mesma do EF6. Eu estou usando o salvamento síncrono, mas todos os métodos assíncronos estão lá, assim como:

public void StoreBeers(List<Beer> beers) {
  using (var context = new BreweryContext()) {
    context.Beers.AddRange(beers);
    context.SaveChanges();
  }
}

E uma simples consulta:

using (var context = new BreweryContext()) {
       return context.Breweries.Where(b=>b.Location.Contains("Vermont"));
}

Eu estou usando a versão do EF7 que está nos pacotes com a versão beta2-11616. O EF7 não é realmente o beta deste momento, mas o "beta2" está relacionado a uma decisão de nomenclatura do pacote NuGet. No momento em que este artigo é publicado, o EF7 terá evoluído ainda mais, então considere este uma aparência, não uma promessa.

Eu ainda tenho um DbContext e defino o DbSets, assim como eu sempre fiz. O OnModelCreating ainda está lá, embora eu não esteja usando ele aqui.

O EF4.1 introduziu o API do DbContext, que era muito mais focado no uso do EF típico. Por baixo, ele ainda se baseou no ObjectContext original, que fornece interação do banco de dados, gerencia transações e acompanha o estado dos objetos. Desde então, o DbContext se tornou a classe padrão para usar e você mergulhar nos APIs de níveis inferiores se quiser fazer uma interação rara com o ObjectContext. O EF7 lançará o ObjectContext pesado; apenas o DbContext permanecerá. Mas algumas destas tarefas que você já lançou no ObjectContext ainda estarão acessíveis.

Alguns dos mapeamentos muito complicados que são difíceis de suportar e não são comumente usados irão embora com o EF7. A publicação do blog mencionado acima diz: "por exemplo, você pode ter uma hierarquia herdada que combinava com mapeamentos TPH, TPT e TPC, bem como com Entity Splitting, todos na mesma hierarquia". Se você já tentou trabalhar diretamente com o API MetadataWorkspace e fugir gritando, você sabe que é um monstro complexo e intrincado, útil para ser capaz de suportar esse tipo de flexibilidade. Mas essa complexidade impediu que a equipe fosse capaz de suportar outros cenários que os usuários solicitaram. Ao simplificar as possibilidades de mapeamento, o API MetadataWorkspace também se tornou mais simples e muito mais flexível. Você pode facilmente obter os metadados sobre o seu esquema de modelo do API DbContext no EF7, que lhe dá uma capacidade de baixo nível para realizar técnicas avançadas sem ter que ter o ObjectContext de baixo nível à sua disposição.

Removendo o EDMX, mas o banco de dados permanecerá primeiro

O Entity Framework atualmente tem duas formas de descrever um modelo. Um usa um EDMX no designer; o outro envolve as classes, um DbContext e mapeamentos que são usados pelos APIs do Code First. Se você está usando o EDMX e designer, no tempo de execução, o EF cria um modelo na memória do XML atrás do EDMX. Se você escolher o caminho do Code First, o EF cria o mesmo modelo na memória ao ler as classes, o DbContext e os mapeamentos que você forneceu. Deste ponto em diante, o EF funciona da mesma forma, independente de como você descreve seu modelo. Observe que com o fluxo de trabalho do EDMX/Designer, você também terá casses POCO e um DbContext para funcionar junto com o seu código. Mas pelo fato do EDMX estar lá, eles não são usados para criar esse modelo na memória. Isso é importante para compreender, conforme você lê as sequências a seguir: O EF7 não suportará o modelo EDMX com base no designer. Ele não terá a capacidade de ler o EDMX XML no tempo de execução para criar o modelo na memória. Ele usará apenas o fluxo de trabalho do Code First.

Quando a equipe escreveu sobre isso, causou pânico entre os desenvolvedores. Em parte, isso se deveu ao fato de que muitos ainda não percebem que você pode reverter a engenharia de um banco de dados para as classes POCO, DbContext e mapeamentos. Em outras palavras, você pode começar com um banco de dados para obter um modelo do Code First. Isso tem sido possível desde que o EF Power Tools Beta foi lançado pela primeira vez no início de 2011. Ele é suportado pelo designer EF6.1 e definitivamente será suportado pelo EF7. Eu já disse muitas vezes que o apelido "Code First" é um pouco confuso e enganoso. Ele era originalmente chamado de "Code Only", mas o nome foi alterado para "Code First" para formar uma boa correspondência com o "Database First" e o "Model First".

Então você não precisa do designer ou de um EDMX para começar com um banco de dados existente.

Mas e se você tem modelos EDMX existentes e não quer perder a capacidade de usar um designer? Existe designers de terceiros que suportam o Entity Framework, como o LLBLGen Pro Designer, que já suporta o EF Code First (bit.ly/11OLlN2), e o Devart Entity Developer (bit.ly/1yHWbB2). Procure por estas ferramentas e possivelmente outras para fornecer potencialmente suporte ao designer para o EF7.

Existe ainda um outro caminho para levar em consideração: manter o EF6!

Superfície menor, mais dispositivos e sistemas operacionais

Além disso, a Microsoft se esforçou para otimizar a distribuição dos APIs do EF. A pasta do pacote NuGet para EF6.1.1 é de cerca de 22MB. Isso inclui um conjunto de 5.5MB para o .NET Framework 4.5 e outro no caso de você estar usando o .NET Framework 4. Com o EF7, existe um número de DLLs menores. Você combinará apenas dos DLLs necessários para suportar seu fluxo de trabalho. Por exemplo, se você está direcionando o SQL Server, você pode usar um EntityFramework.dll de núcleo, um DLL para o SQL Server e outro com os APIs comuns para armazenamentos de dados relacionais. Se você quiser usar migrações, este é um conjunto separado que você pode pular. Caso contrário, você pode querer criar e executar migrações a partir do Console do Gerente de Pacote. Existe um API para comandos. Ao usar o gerente de pacote do NuGet, os pacotes adequados serão identificados e baixados através de suas dependências, assim você não terá que se preocupar demais com os detalhes.

O que isso faz é minimizar a superfície do EF7 no computador ou dispositivo do usuário final, que é especificamente importante nos dispositivos. O ASP.NET está indo por este caminho também. Ambas estas tecnologias estão abandonando suas dependências em relação ao .NET Framework. Em vez disso, eles distribuirão apenas os DLLs necessários para realizar as tarefas de um determinado aplicativo. Isso significa que a versão já eficiente do .NET usada pelos aplicativos do Windows Phone e Windows Store serão capazes de usar o EF7.

Isso também significa que sistemas operacionais como OS X e Linux que usam Mono em vez do .NET Framework completo também serão capazes de suportar o Entity Framework do lado do cliente.

Além do relacional

Quando o Entity Framework foi introduzido pela primeira vez, a Microsoft teve uma visão de estar sendo usada para uma variedade de armazenamentos de dados, embora a primeira passagem focou nos bancos de dados relacionais. Os bancos de dados não relacionais existiam nesta época, mas não eram amplamente usados, ao contrário dos bancos de dados NoSQL - especialmente os bancos de dados de documentos - que são tão populares hoje.

Enquanto o EF é um ORM (Mapeador Relacional do Objeto), os desenvolvedores que usam querem ser capazes de usar as mesmas construções para interagir com bancos de dados não relacionais. O EF7 fornecerá um alto nível de suporte para isso, mas não se esqueça do que o nível alto realmente significa. Existem grandes diferenças entre os bancos de dados relacionais e os bancos de dados não relacionais e o EF não fará qualquer tentativa de mascarar essas diferenças. Mas para a consulta e atualizações básicas, você será capaz de usar os padrões com os quais você já está familiarizado.

A Figura 1 mostra o código de um aplicativo de amostra que tem como alvo o Microsoft Azure Table Storage, que é um banco de dados de documento não relacional. A amostra vem do Gerente de Programa do EF, Rowan Miller, em github.com/rowanmiller/Demo-EF7. Observe que a amostra é executada em reação a versão 11514 das criações noturnas alfa do EF7.

Figura 1 Um DbContext definido para funcionar com o Azure Table Storage

public class WarrantyContext : DbContext
{
  public DbSet<WarrantyInfo> Warranties { get; set; }
  protected override void OnConfiguring(DbContextOptions options) {
    var connection =
      ConfigurationManager.ConnectionStrings["WarrantyConnection"]
                        .ConnectionString;
    options.UseAzureTableStorage(connection);
  }
  protected override void OnModelCreating(ModelBuilder builder) {
    builder.Entity<WarrantyInfo>()
           .ForAzureTableStorage()
           .PartitionAndRowKey(w => w.BikeModelNo, w => w.BikeSerialNo);
  }
}

O método OnConfiguring é novo. É uma forma de afetar como o EF configura o DbContext no tempo de execução, um pouco como você pode fazer hoje com a classe DbConfiguration. Observe o método de extensão builder.UseAzureTableStorage, que existe pois eu também instalei o pacote EntityFramework.AzureTableStorage no meu projeto.

O EF7 usa estes padrões para seus vários provedores. Está aqui um método OnConfiguring em uma classe DbContext dentro de um projeto que tem como alvo SQLite:

protected override void OnConfiguring(DbContextOptions builder) {
  string dir = ApplicationData.Current.LocalFolder.Path;
  string connection = "Filename=" + Path.Combine(dir, "VermontBrewery.db");
  builder.UseSQLite(connection);
}

Este projeto tem um pacote EntityFramework.SQLite instalado, então agora eu tenho o método de extensão UseSQLite no lugar.

De volta à classe WarrantyContext na Figura 1, você pode ver o OnModelCreating familiar substituir para o DbContext e lá eu estou fazendo algum mapeamento especial. Mais uma vez, eu tenho métodos fornecidos pelo pacote NuGet do EntityFramework.AzureTableStorage. Eu escolho os pacotes que quero com base nos recursos que eu preciso. O Azure Table Storage depende de um par chave-valor para a identidade única e para suportar o particionamento da tabela. A fim de recuperar ou armazenar dados, é fundamental saber quais valores são usados para o PartitionKey e o PartitionKey, para que o API forneça um método - PartitionAndRowKey - que permite que você mapeie as propriedades para as chaves adequadas. O conceito não é diferente de como você foi capaz de usar o API fluente ou as Anotações dos Dados para especificar a propriedade que mapeia para uma chave principal do banco de dados relacional.

Graças a esse mapeamento, eu posso escrever uma consulta LINQ familiar para recuperar alguns dados:

var warranty = _context.Warranties
          .Where(w =>
            w.BikeModelNo == modelNo
            && w.BikeSerialNo == serialNo)
          .SingleOrDefault();

Então, você está vendo uma consulta LINQ típica, mas ela está sendo executada em relação ao armazenamento de dados do Azure Table Storage, assim como você pode fazer com um banco de dados relacional hoje.

Esta mesma demonstração também atualiza os objetos de garantia; cria e insere novos usando DbSet.Add; e usa o DbContext.SaveChanges para persistir tudo de volta para o armazenamento de dados, assim como é feito hoje com o EF6 - e tem sido feito ao longo da história do EF.

Também é interessante considerar como o Entity Framework sempre suportou um conjunto de recursos canônicos para o mapeamento de banco de dados relacionais, mas permite que até os provedores do banco de dados especifique quais deles devem traduzir seus alvos para o banco de dados. O EF7 terá um conjunto de alto nível de recursos canônicos que podem ser compreendidos pelos armazenamentos de dados relacionais e não relacionais. Existe também um conjunto de nível inferior de recursos que foca nos bancos de dados relacionais, e eles estão encapsulados no conjunto do EntityFramework.Relational. Todos os provedores do banco de dados relacional dependerá daqueles e, tal como hoje, o seu manuseio específico da interação do banco de dados será hospedado em seus próprios APIs dos provedores, como o EntityFramework.SQLite que eu usei anteriormente. Você localizará os métodos de extensão nos provedores que criam um método AsRelational, que estão no API relacional. É um método de extensão do DbContext.

Existe até mesmo um provedor de armazenamento de dados na memória, que é para testes de unidade, quando você quer evitar uma interação de banco de dados que pode estar envolvido na lógica que você está testando. Normalmente nestes cenários você usa estruturas de imitação ou falsificação para representar a interação do banco de dados.

Se você estiver configurando um teste para realizar uma consulta ou atualização do banco de dados, você tem algum código para criar uma instância do banco de dados, tal como:

using (var context = new BreweryContext()) {
  // Perform some action against the context
}

Você pode facilmente mudar para um armazenamento na memória ao instalar primeiro o pacote entityframework.InMemory para o seu projeto de teste, definindo um DbContextOption para o InMemoryStore e, em seguida, especificando que o contexto deve usar essa opção. Novamente, isso é possível graças aos métodos de extensão fornecidos por este API:

var options = new DbContextOptions().UseInMemoryStore();
using (var context = new BreweryContext(options)){
  // Perform some action against the context
}

Mais recursos, mais capacidades, muito mais flexível

Você já pode ver os benefícios da nova base de código na flexibilidade dos métodos de extensão fornecidos, e na capacidade de afetar o pipeline do Entity Framework com a sobrecarga OnConfiguring. Existem pontos de extensividade em toda a base do novo código, não apenas para mudar o EF7, mas também para torná-lo mais simples para que você conecte sua própria lógica ao EF7.

A nova base de código do núcleo dá a equipe EF uma chance de resolver alguns problemas antigos. Por exemplo, a versão que estou usando já tem suporte para a atualização em lote, que é o padrão para bancos de dados relacionais. Eu reproduzi o código que me permite usar meus próprios métodos em linha nas consultas LINQ sem receber a terrível mensagem "O Entity Framework não pode traduzir este método no SQL". Em vez disso, o EF e os provedores são capazes de analisar qual parte da consulta se tornará SQL e qual será executada localmente no cliente. Tenho certeza de que haverá proteção e orientação para evitar alguns problemas potenciais de desempenho para esse recurso particular.

A equipe foi capaz de adicionar a capacidade do Unique Foreign Keys solicitado ao longo para modelos. Eles também estão procurando de perto fornecer suporte para funções de valor de tabela e formas mais limpas de lidar com dados desconectados, o que é algo que eu tenho focado por muitos anos com o Entity Framework. É um problema comum com aplicativos desconectados - não apenas quando o Entity Framework está envolvido - e não é fácil criar algoritmos que funcionarão de forma consistente em todos os cenários. Então uma nova abordagem é necessário, com certeza.

Há muito mais para ficar animado sobre isso com o EF7. Eu recomendo um olhar mais atento nas postagens sobre ADO.NET Team Blog em blogs.msdn.com/adonet. Além desse post que eu vinculei mais cedo, Rowan Miller escreveu de forma aprofundada sobre a decisão de abandonar o suporte ao designer no EF7; consulte "EF7 - What Does 'Code First Only' Really Mean" em bit.ly/1sLM3Ur. Fique de olho nesse blog, bem como no projeto GitHub. O Wiki do GitHub (bit.ly/1viwqXu) tem links sobre como acessar as criações noturnas; como baixar, compilar e depurar o código-fonte; alguns passo-a-passo e as notas de reuniões do projeto. A equipe está ansiosa pelo seu feedback e está animada para receber as solicitações pull.

Uma decisão não tomada de forma simples

É importante para mim escrever sobre o EF7 para ajudar a aliviar alguns temores sobre uma mudança muito grande e que alguns dos recursos EF existentes que podem ser parte integrante de seus aplicativos não se tornarão no EF7. Esses temores são têm fundamento e a equipe não está levando-os levemente, e nem eu. Mas compreendendo que o EF6 não irpa embora e continuará a evoluir com as contribuições da comunidade é fundamental. Se quiser aproveitar o movimento de avanço, você terá algumas escolhas difíceis a fazer. Atualizar os aplicativos grandes não será fácil e você deve pesar cuidadosamente as opções. Talvez você possa dividir seu aplicativo, reescrever somente algumas partes para se beneficiar do EF7.

Novamente, conforme eu estou escrevendo esta coluna, o EF7 ainda está nos seus estágios iniciais, e eu não tenho certeza de quão longe estará pelo tempo que você lê isso. Mas a fonte e os pacotes NuGet disponíveis atualmente estão lá para explorar, experimentar e fornecer feedback. Tenha em mente que a equipe pode não manter sempre todos os APIs do provedor (tais como Redis, SQLite e outros) atualizados, conforme eles evoluem o API nuclear. De acordo com a publicação em bit.ly/1ykagF0, "EF7 - Priorities, Focus and Initial Release", a primeira versão do EF7 focará na compatibilidade com o ASP.NET 5. As versões subsequentes adicionarão mais recursos. Ainda assim, mesmo que o EF7 ainda não esteja estável o suficiente para começar a criar aplicativos, definitivamente existem o suficiente para permitir que você comece a planejar com antecedência.


Julie Lerman é MVP da Microsoft, mentora e consultora do .NET, que reside nas colinas de Vermont. Você pode encontrar ela apresentando sobre o acesso a dados e outros tópicos do .NET em grupos de usuário e conferências pelo mundo todo. Ela bloga em thedatafarm.com/blog e é a autora do “Programming Entity Framework” (2010), bem como de Code First edition (2011) e DbContext edition (2012), todos de O’Reilly Media. Siga Julie no Twitter em twitter.com/julielerman e confira seus cursos da Pluralsight em juliel.me/PS-Videos.

Agradecemos ao seguinte especialista técnico da Microsoft pela revisão deste artigo: Rowan Miller

Isso é baseado na versão alpha do Entity Framework 7. Todas as informações estão sujeitas a alteração.