EF Core no .NET 11 Preview 5: novidades, melhorias e breaking changes
O EF Core no .NET 11 Preview 5 trouxe um conjunto relevante de atualizações, que vão da ferramenta de linha de comando dotnet ef até otimizações na tradução de consultas e recursos novos para SQL Server e Azure Cosmos DB. Neste artigo, você vê cada novidade dessa versão de preview, com exemplos de código e referências à documentação oficial.
Como se trata de uma preview, as APIs ainda podem mudar até a versão final. Mesmo assim, acompanhar cada etapa ajuda a planejar a migração e a identificar breaking changes com antecedência.
Visão geral do EF Core no .NET 11 Preview 5
As notas de lançamento oficiais organizam as mudanças do EF Core no .NET 11 Preview 5 em sete frentes principais.
Primeiro, o dotnet ef passa a suportar aplicações file-based. Em seguida, a ferramenta ganha um arquivo de configuração com valores padrão.
Além disso, o pacote de analisadores recebe o diagnóstico EF1004, e o provider do SQL Server adota o SQL Server 2022 como compatibilidade padrão.
Também entram o mapeamento das colunas de período temporal para propriedades CLR, os namespaces file-scoped no código gerado e um SQL mais limpo em algumas traduções.
Por fim, a versão inclui dois breaking changes e uma lista de correções de bugs. Vale lembrar que o EF Core 11 exige o SDK e o runtime do .NET 11 e não roda em versões anteriores nem no .NET Framework.
Suporte a aplicações file-based no dotnet ef
A partir do Preview 5, a ferramenta dotnet ef passou a suportar aplicações C# baseadas em arquivo. Esse é o modelo de aplicação em um único arquivo introduzido no .NET 10.
Os comandos de migrations e de scaffolding agora aceitam os parâmetros --file e --startup-file. O primeiro indica o arquivo da aplicação, enquanto o segundo aponta o arquivo de inicialização em tempo de design, quando ele for diferente.
dotnet ef migrations add InitialCreate --file .\App.cs
dotnet ef dbcontext scaffold \
"Data Source=app.db" \
Microsoft.EntityFrameworkCore.Sqlite \
--file .\Model.cs \
--startup-file .\App.cs
O fluxo tradicional com --project e --startup-project continua funcionando normalmente em projetos no formato SDK. Ou seja, as duas opções convivem sem conflito.
Essa versão também melhora o diagnóstico da ferramenta. Quando a saída do build de metadados contém o erro raiz do MSBuild ou do SDK, o dotnet ef agora exibe esse erro diretamente, em vez de trocá-lo por uma mensagem genérica.
Na prática, isso encurta a investigação quando um comando falha. Você vê a causa real logo na primeira execução.
Arquivo de configuração para o dotnet ef
Uma das melhorias mais práticas do EF Core no .NET 11 Preview 5 é o arquivo .config/dotnet-ef.json. Com ele, você define valores padrão para as opções mais usadas da ferramenta.
Dessa forma, não é mais necessário repetir argumentos como --project e --startup-project em cada comando.
{
"project": "src/App.Infrastructure",
"startupProject": "src/App.Api",
"framework": "net11.0",
"configuration": "Debug",
"context": "AppDbContext",
"runtime": "win-x64",
"verbose": true
}
A ferramenta procura esse arquivo percorrendo a árvore de diretórios a partir do diretório de trabalho atual, e usa o primeiro que encontrar.
As opções explícitas na linha de comando sempre têm precedência sobre o arquivo. Além disso, os caminhos relativos de project e startupProject partem do diretório pai da pasta .config.
Como o arquivo fica dentro do repositório, você pode versioná-lo. Assim, toda a equipe compartilha a mesma configuração dos comandos de migration.
EF1004 e consultas async executadas de forma síncrona
O pacote de analisadores do EF Core recebeu um novo diagnóstico, o EF1004. Ele alerta quando o código chama System.Linq.AsyncEnumerable.ToAsyncEnumerable() sobre uma IQueryable<T>.
Esse método envolve uma enumeração síncrona em um IAsyncEnumerable<T>. Por isso, a consulta pode rodar de forma síncrona, fora do pipeline assíncrono do EF Core.
// EF1004: pode avaliar a consulta EF de forma síncrona
await foreach (var blog in blogsQuery.ToAsyncEnumerable())
{
Console.WriteLine(blog.Name);
}
// Correto: utiliza o pipeline async nativo do EF Core
await foreach (var blog in blogsQuery.AsAsyncEnumerable())
{
Console.WriteLine(blog.Name);
}
Para consultas do EF Core, o método recomendado é AsAsyncEnumerable(). Ele garante que a consulta ao banco passe pelo pipeline assíncrono do framework.
Esse erro é sutil, porque o código compila e parece assíncrono. Contudo, ele pode bloquear threads sob carga, então o aviso no build evita um problema difícil de diagnosticar em produção.
SQL Server 2022 como compatibilidade padrão
No EF Core no .NET 11 Preview 5, o provider do SQL Server passou a usar o nível de compatibilidade 160 por padrão, que corresponde ao SQL Server 2022.
Com isso, novas aplicações usam traduções que dependem da sintaxe do SQL Server 2022 sem configuração extra. Segundo a documentação, isso inclui funções como LEAST e GREATEST.
Aplicações que precisam manter compatibilidade com versões anteriores podem definir o nível explicitamente:
optionsBuilder.UseSqlServer(
connectionString,
sqlServerOptions => sqlServerOptions.UseCompatibilityLevel(150));
Antes de atualizar, confira qual versão do SQL Server roda em cada ambiente. Se algum deles ainda usa uma versão anterior, então defina o nível de compatibilidade manualmente para evitar SQL incompatível.
O mesmo mecanismo vale no sentido oposto. A documentação do EF Core 11 mostra o nível 170 para habilitar traduções do SQL Server 2025, como o JSON_CONTAINS.
Propriedades de período temporal no EF Core no .NET 11
Antes, as colunas de período PeriodStart e PeriodEnd das tabelas temporais do SQL Server precisavam ser shadow properties. Em outras palavras, elas existiam apenas no modelo do EF, sem propriedades correspondentes na classe .NET.
A partir do EF Core no .NET 11 Preview 5, você pode mapear essas colunas para propriedades CLR comuns da entidade.
public class Employee
{
public Guid EmployeeId { get; set; }
public string Name { get; set; }
public string Position { get; set; }
public DateTime PeriodStart { get; set; }
public DateTime PeriodEnd { get; set; }
}
modelBuilder
.Entity<Employee>()
.ToTable(
"Employees",
b => b.IsTemporal(
b =>
{
// mapeia as colunas de período para propriedades CLR
b.HasPeriodStart(e => e.PeriodStart);
b.HasPeriodEnd(e => e.PeriodEnd);
}));
Com esse mapeamento, as consultas LINQ referenciam as propriedades de período diretamente, sem EF.Property(...).
var history = context.Employees
.TemporalAll()
.OrderBy(e => e.PeriodStart)
.Select(e => new { e.Name, e.PeriodStart, e.PeriodEnd })
.ToList();
As propriedades continuam configuradas com ValueGenerated.OnAddOrUpdate. Portanto, o SQL Server sempre gera os valores, e o EF Core os exclui das instruções INSERT e UPDATE.
O ganho aparece principalmente em telas de auditoria e histórico. Nesses cenários, o código fica tipado e mais legível do que com strings em EF.Property.
C# gerado com namespaces file-scoped
Todo o código C# que o EF Core gera agora usa namespaces no formato file-scoped. Assim, a saída fica alinhada com os templates modernos de projetos .NET.
A mudança elimina um nível de indentação. Ela vale para migrations, snapshots de modelo, modelos compilados e código gerado por engenharia reversa.
namespace MyApp.Migrations;
public partial class InitialCreate : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
// ...
}
}
A diferença parece cosmética. No entanto, ela melhora a leitura de arquivos com muitas entidades ou configurações extensas.
Em projetos existentes, as próximas migrations já virão no novo formato. Por isso, vale avisar a equipe para não estranhar a diferença de estilo entre arquivos antigos e novos nas revisões de código.
SQL mais limpo no EF Core no .NET 11 Preview 5
O EF Core no .NET 11 Preview 5 traz duas melhorias relevantes na qualidade do SQL gerado.
Remoção de casts redundantes
A primeira melhoria remove casts SQL redundantes. Eles surgiam de tipos CLR com value converters que têm conversão implícita para o tipo do provider.
Antes, o EF Core podia gerar algo como CAST([u].[Name] AS nvarchar(max)) em uma coluna que já era nvarchar(max). Agora, os predicados sobre essas propriedades evitam o CAST desnecessário.
var users = await context.Users
.Where(u => EF.Functions.Like(u.Name, "Name%"))
.ToListAsync();
SELECT [u].[Id], [u].[Name]
FROM [Users] AS [u]
WHERE [u].[Name] LIKE N'Name%'
Segundo a documentação, essa limpeza vai além da estética. Sem o CAST em volta da coluna, o banco consegue usar os índices definidos nela, o que pode melhorar bastante a performance da consulta.
Any sobre propriedades byte[]
A segunda melhoria traduz Any() sobre propriedades do tipo byte[] no SQL Server e no SQLite.
var withPayload = await context.Documents
.Where(d => d.Payload.Any())
.ToListAsync();
No SQL Server, a tradução resultante é DATALENGTH([b].[Bytes]) > 0. Já no SQLite, a tradução é length("b"."Bytes") > 0.
Dessa forma, o banco verifica se a sequência de bytes tem conteúdo sem trazer dados binários para a aplicação.
Breaking changes do EF Core no .NET 11 Preview 5
O EF Core no .NET 11 Preview 5 introduz dois breaking changes que merecem atenção antes de qualquer atualização.
O primeiro é a remoção das APIs marcadas como obsoletas antes do EF Core 11. Portanto, todo código que ainda usa essas APIs precisa migrar para os substitutos indicados antes do upgrade.
Uma boa estratégia é tratar os avisos de obsolescência do EF Core 10 como erros antes de mudar de versão. Assim, o compilador aponta cada ponto que vai quebrar.
O segundo envolve a geração de id no Azure Cosmos DB. Quando o EF Core gera valores de id a partir de chaves compostas, ele não escapa mais caracteres ilegais.
Aplicações com dados existentes que dependem de IDs escapados precisam revisar esse comportamento com cuidado. Caso contrário, documentos antigos e novos podem acabar com formatos de id diferentes.
Correções de bugs do EF Core no .NET 11 Preview 5
Além das novidades, o EF Core no .NET 11 Preview 5 inclui correções importantes para cenários do dia a dia.
Os métodos EnsureCreated, EnsureCreatedAsync, Migrate e MigrateAsync agora usam uma estratégia de execução com retry em falhas transitórias. Antes, isso podia causar falhas desnecessárias em ambientes com conectividade instável.
O comando dotnet ef migrations bundle --configuration agora repassa nomes de configuração customizados. Antes, a ferramenta aceitava apenas Debug ou Release.
Na construção de modelos, tipos com escopo de arquivo agora funcionam como entity types sem lançar IndexOutOfRangeException. Também as lambdas de configuração de complex properties encadeiam corretamente em tipos complexos que não são coleções.
As mensagens de erro para membros conflitantes agora informam o tipo do membro existente. Além disso, elas orientam você a removê-lo antes de prosseguir.
No scaffolding do SQLite, a engenharia reversa agora ignora a tabela interna __EFMigrationsLock. Esse comportamento já existia para __EFMigrationsHistory, mas faltava para essa tabela.
Por fim, usar EF.Constant() ou EF.Parameter() dentro de compiled queries ou query filters agora lança uma InvalidOperationException com mensagem clara. Antes, o erro era uma InvalidCastException genérica.
O EF Core no .NET 11 além do Preview 5
O Preview 5 faz parte de um ciclo maior. Segundo a página de novidades do EF Core 11 no Microsoft Learn, a versão traz melhorias importantes para o SQL Server 2025.
Entre elas estão o suporte experimental a VECTOR_SEARCH() e a índices vetoriais. Além disso, as propriedades vetoriais saem por padrão das projeções de entidade, o que evita transferir dados volumosos sem necessidade.
A versão também traduz Contains em coleções primitivas para JSON_CONTAINS e adiciona funções de pesquisa de texto completo com valor de tabela, como FREETEXTTABLE e CONTAINSTABLE.
No Azure Cosmos DB, o EF Core 11 adiciona suporte completo a tipos complexos, lotes transacionais por padrão, execução em massa e gerenciamento de tokens de sessão.
Nas migrations, chegam o dotnet ef database update --add, que cria e aplica uma migration em uma única etapa, e o ExcludeForeignKeyFromMigrations(), que omite a constraint de chave estrangeira no banco.
O snapshot do modelo também passa a registrar o ID da migration mais recente. Com isso, branches divergentes geram conflito de merge e a equipe percebe o problema cedo.
Há ainda um SQL melhor em joins para navegações de referência, com remoção de joins e colunas de ORDER BY desnecessários. Para acompanhar as mudanças da versão seguinte, veja o artigo sobre as novidades do EF Core 11 no Preview 7.
As demais áreas da plataforma também evoluíram nessa preview. Para completar o panorama, veja o artigo sobre o SDK e as ferramentas do .NET 11 Preview 5.
Como testar o EF Core no .NET 11 Preview 5
Para experimentar o EF Core no .NET 11 Preview 5, primeiro instale o SDK do .NET 11 Preview 5. Depois, atualize os pacotes Microsoft.EntityFrameworkCore do projeto para as versões preview correspondentes.
A ferramenta de linha de comando também precisa acompanhar a versão. Assim, os novos parâmetros e o arquivo de configuração ficam disponíveis.
# atualiza a ferramenta global para a versão preview mais recente
dotnet tool update --global dotnet-ef --prerelease
Faça esse teste em um branch separado e com um banco descartável. Dessa forma, você avalia os breaking changes sem arriscar dados reais.
Conclusão
O EF Core no .NET 11 Preview 5 entrega melhorias práticas que afetam diretamente o dia a dia de desenvolvimento.
O suporte a aplicações file-based e o arquivo de configuração do dotnet ef reduzem atrito operacional. Ao mesmo tempo, o diagnóstico EF1004 previne bugs sutis de execução síncrona em código assíncrono.
A compatibilidade padrão com SQL Server 2022 abre caminho para novas traduções. Já o mapeamento das propriedades de período simplifica as consultas sobre tabelas temporais.
Por fim, o SQL mais limpo e os namespaces file-scoped melhoram a qualidade do código gerado. Portanto, vale testar o EF Core no .NET 11 Preview 5 em um branch separado e mapear os breaking changes antes da versão final.
FAQ
O suporte a apps file-based substitui o fluxo com --project e --startup-project?
Não. Os dois fluxos coexistem, e --file e --startup-file atendem apenas o modelo de aplicação em arquivo único do .NET 10 em diante.
Posso versionar o arquivo .config/dotnet-ef.json no repositório?
Sim. A ferramenta encontra o arquivo percorrendo a árvore de diretórios, então você pode incluí-lo no repositório para padronizar as configurações da equipe.
O que acontece se eu usar ToAsyncEnumerable em vez de AsAsyncEnumerable?
A consulta pode rodar de forma síncrona e bloquear a thread. O diagnóstico EF1004 emite um aviso no build para sinalizar esse uso.
Preciso mudar algo no código por causa do SQL Server 2022 como padrão?
Não, desde que o banco seja SQL Server 2022 ou superior. Para versões anteriores, defina o nível com UseCompatibilityLevel() nas opções do provider.
Mapear PeriodStart e PeriodEnd para propriedades CLR muda os INSERT e UPDATE?
Não. As propriedades continuam com ValueGenerated.OnAddOrUpdate, então o EF Core as exclui das instruções de escrita.
O breaking change no id do Cosmos DB afeta todos os usuários?
Afeta principalmente aplicações com dados existentes cujos IDs, gerados a partir de chaves compostas, dependem do escape de caracteres ilegais. Revise esse cenário antes de atualizar.
Qual o impacto real da remoção de casts redundantes?
O SQL fica mais legível e, segundo a documentação, o banco pode usar os índices da coluna. Isso pode melhorar bastante a performance da consulta.