Novos recursos no EF Core 2.1
Além de várias correções de bug e pequenos aprimoramentos funcionais e de desempenho, o EF Core 2.1 inclui alguns novos recursos atraentes:
Carregamento lento
O EF Core agora contém os elementos essenciais necessários para que qualquer pessoa possa criar classes de entidade que carreguem suas propriedades de navegação sob demanda. Também criamos um novo pacote, Microsoft.EntityFrameworkCore.Proxies, que aproveita esses blocos de construção para produzir classes proxy de carregamento lentas com base em classes de entidade minimamente modificadas (por exemplo, classes com propriedades de navegação virtual).
Leia a seção sobre o carregamento lento para obter mais informações sobre este tópico.
Parâmetros em construtores de entidade
Como um dos blocos de construção necessários para o carregamento lento, habilitamos a criação de entidades que recebem parâmetros em seus construtores. Você pode usar parâmetros para injetar valores de propriedade, delegados de carregamento lento e serviços.
Leia a seção no construtor de entidade com parâmetros para obter mais informações sobre este tópico.
Conversões de valor
Até agora, o EF Core só podia mapear propriedades de tipos com suporte nativo pelo provedor de banco de dados subjacente. Os valores foram copiados entre colunas e propriedades sem nenhuma transformação. A partir do EF Core 2.1, as conversões de valor podem ser aplicadas para transformar os valores obtidos de colunas antes de serem aplicados às propriedades e vice-versa. Temos várias conversões que podem ser aplicadas por convenção conforme necessário, bem como uma API de configuração explícita que permite registrar conversões personalizadas entre colunas e propriedades. Alguns dos aplicativos desse recurso são:
- Armazenando enumerações como cadeias de caracteres
- Mapeando inteiros sem sinal com o SQL Server
- Criptografia automática e decodificação de valores de propriedade
Leia a seção sobre conversões de valor para obter mais informações sobre este tópico.
Tradução do LINQ GroupBy
Antes da versão 2.1, no EF Core, o operador GROUPBy LINQ sempre seria avaliado na memória. Agora, damos suporte à conversão para a cláusula SQL GROUP BY na maioria dos casos comuns.
Este exemplo mostra uma consulta com GroupBy usada para calcular várias funções de agregação:
var query = context.Orders
.GroupBy(o => new { o.CustomerId, o.EmployeeId })
.Select(g => new
{
g.Key.CustomerId,
g.Key.EmployeeId,
Sum = g.Sum(o => o.Amount),
Min = g.Min(o => o.Amount),
Max = g.Max(o => o.Amount),
Avg = g.Average(o => o.Amount)
});
A tradução SQL correspondente tem esta aparência:
SELECT [o].[CustomerId], [o].[EmployeeId],
SUM([o].[Amount]), MIN([o].[Amount]), MAX([o].[Amount]), AVG([o].[Amount])
FROM [Orders] AS [o]
GROUP BY [o].[CustomerId], [o].[EmployeeId];
Propagação de dados
Com a nova versão, será possível fornecer dados iniciais para preencher um banco de dados. Diferentemente do EF6, a propagação de dados está associada a um tipo de entidade que faz parte da configuração do modelo. Em seguida, as migrações do EF Core podem calcular automaticamente quais operações de inserção, atualização ou exclusão precisam ser aplicadas ao atualizar o banco de dados para uma nova versão do modelo.
Por exemplo, você pode usá-lo para configurar dados iniciais de um post no OnModelCreating
:
modelBuilder.Entity<Post>().HasData(new Post{ Id = 1, Text = "Hello World!" });
Leia a seção sobre propagação de dados para obter mais informações sobre este tópico.
Tipos de consulta
Um modelo do EF Core agora pode incluir tipos de consulta. Ao contrário dos tipos de entidade, os tipos de consulta não têm chaves definidas neles e não podem ser inseridos, excluídos ou atualizados (ou seja, são somente leitura), mas podem ser retornados diretamente por consultas. Alguns dos cenários de uso para tipos de consulta são:
- Mapeamento para exibições sem chaves primárias
- Mapeamento para tabelas sem chaves primárias
- Mapeamento para consultas definidas no modelo
- Servir como o tipo de retorno para consultas
FromSql()
Leia a seção sobre tipos de consulta para obter mais informações sobre este tópico.
Include para tipos derivados
Agora será possível especificar propriedades de navegação definidas apenas em tipos derivados ao escrever expressões para o método Include
. Para obter a versão fortemente tipada do Include
, há suporte tanto para o uso de uma conversão explícita quanto do operador as
. Agora também há suporte para referenciar os nomes da propriedade de navegação definida nos tipos derivados na versão de cadeia de caracteres do Include
:
var option1 = context.People.Include(p => ((Student)p).School);
var option2 = context.People.Include(p => (p as Student).School);
var option3 = context.People.Include("School");
Leia a seção sobre Incluir com tipos derivados para obter mais informações sobre este tópico.
Suporte para System.Transactions
Adicionamos a capacidade de trabalhar com recursos do System.Transactions, como o TransactionScope. Isso funcionará no .NET Framework e no .NET Core ao usar provedores de banco de dados que dão suporte a ele.
Leia a seção sobre System.Transactions para obter mais informações sobre este tópico.
Melhor ordenação de coluna na migração inicial
Com base nos comentários do cliente, atualizamos as migrações para gerar inicialmente colunas para tabelas na mesma ordem em que as propriedades são declaradas nas classes. Observe que o EF Core não pode alterar a ordem quando novos membros são adicionados após a criação da tabela inicial.
Otimização de subconsultas correlacionadas
Melhoramos nossa tradução de consulta para evitar a execução de consultas SQL "N + 1" em muitos cenários comuns em que o uso de uma propriedade de navegação na projeção leva à junção de dados da consulta raiz com dados de uma subconsulta correlacionada. A otimização requer o buffer dos resultados da subconsulta e exigimos que você modifique a consulta para aceitar o novo comportamento.
Por exemplo, a consulta a seguir normalmente é convertida em uma consulta para Clientes, além de N (em que "N" é o número de clientes retornados) consultas separadas para Pedidos:
var query = context.Customers.Select(
c => c.Orders.Where(o => o.Amount > 100).Select(o => o.Amount));
Ao incluir ToListAsync()
no lugar certo, você indica que o buffer é apropriado para os Pedidos, que permitem a otimização:
var query = context.Customers.Select(
c => c.Orders.Where(o => o.Amount > 100).Select(o => o.Amount).ToList());
Observe que essa consulta será traduzida para apenas duas consultas SQL: uma para Clientes e a próxima para Pedidos.
Atributo [Owned]
Agora é possível configurar tipos de entidade de propriedade simplesmente anotando o tipo com [Owned]
e, em seguida, certificando-se de que a entidade de proprietário seja adicionada ao modelo:
[Owned]
public class StreetAddress
{
public string Street { get; set; }
public string City { get; set; }
}
public class Order
{
public int Id { get; set; }
public StreetAddress ShippingAddress { get; set; }
}
Ferramenta de linha de comando dotnet-ef incluída no SDK do .NET Core
Os comandos dotnet-ef agora fazem parte do SDK do .NET Core, portanto, não será mais necessário usar DotNetCliToolReference no projeto para poder usar migrações ou estruturar um DbContext de um banco de dados existente.
Consulte a seção sobre instalando as ferramentas para obter mais detalhes sobre como habilitar ferramentas de linha de comando para diferentes versões do SDK do .NET Core e do EF Core.
Pacote Microsoft.EntityFrameworkCore.Abstractions
O novo pacote contém atributos e interfaces que você pode usar em seus projetos para iluminar os recursos do EF Core sem depender do EF Core como um todo. Por exemplo, o atributo [Owned] e a interface ILazyLoader estão localizados aqui.
Eventos de alteração de estado
Novos eventos de Tracked
e StateChanged
em ChangeTracker
podem ser usados para escrever a lógica que reage às entidades que entram no DbContext ou alteram seu estado.
Analisador de parâmetro SQL bruto
Um novo analisador de código é incluído no EF Core que detecta usos potencialmente inseguros de nossas APIs de SQL bruto, como FromSql
ou ExecuteSqlCommand
. Por exemplo, para a consulta a seguir, você verá um aviso porque minAge não é parametrizado:
var sql = $"SELECT * FROM People WHERE Age > {minAge}";
var query = context.People.FromSql(sql);
Compatibilidade do provedor de banco de dados
É recomendável que você use o EF Core 2.1 com provedores que foram atualizados ou pelo menos testados para trabalhar com o EF Core 2.1.
Dica
Se você encontrar qualquer incompatibilidade inesperada ou qualquer problema nos novos recursos ou se tiver comentários sobre eles, denuncie-o usando nosso rastreador de problemas.