Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
Os controles de comportamento de rastreamento determinam se o Entity Framework Core mantém informações sobre uma instância de entidade em seu rastreador de alterações. Se uma entidade for acompanhada, quaisquer alterações detectadas na entidade serão persistidas no banco de dados durante SaveChanges
. O EF Core também corrige as propriedades de navegação entre as entidades em um resultado de consulta de acompanhamento e as entidades que estão no rastreador de alterações.
Observação
Tipos de entidade sem chave nunca são rastreados. Onde quer que este artigo mencione tipos de entidade, ele se refere aos tipos de entidade que têm uma chave definida.
Dica
Você pode exibir o exemplo deste artigo no GitHub.
Acompanhamento de consultas
Por padrão, as consultas que retornam tipos de entidade estão em rastreamento. Uma consulta de acompanhamento significa que todas as alterações nas instâncias de entidade são mantidas por SaveChanges
. No exemplo a seguir, a alteração na classificação de blogs é detectada e persistida no banco de dados durante SaveChanges
:
var blog = await context.Blogs.SingleOrDefaultAsync(b => b.BlogId == 1);
blog.Rating = 5;
await context.SaveChangesAsync();
Quando os resultados são retornados em uma consulta de acompanhamento, o EF Core verifica se a entidade já está no contexto. Se o EF Core encontrar uma entidade existente, a mesma instância será retornada, o que pode potencialmente usar menos memória e ser mais rápido do que uma consulta sem acompanhamento. O EF Core não substitui, no registro, os valores atuais e originais das propriedades da entidade pelos valores do banco de dados. Se a entidade não for encontrada no contexto, o EF Core criará uma nova instância de entidade e a anexa ao contexto. Os resultados da consulta não contêm nenhuma entidade que foi adicionada ao contexto. Elas ainda não foram salvas no banco de dados.
Consultas sem rastreamento
Consultas sem rastreamento são úteis quando os resultados são usados em um cenário de apenas leitura. Eles geralmente são mais rápidos de serem executados porque não há necessidade de configurar as informações de controle de alterações. Se as entidades recuperadas do banco de dados não precisarem ser atualizadas, uma consulta sem acompanhamento deverá ser usada. Uma consulta individual pode ser definida como sem acompanhamento. Uma consulta sem acompanhamento também fornece resultados com base no que está no banco de dados desconsiderando quaisquer alterações locais ou entidades adicionadas.
var blogs = await context.Blogs
.AsNoTracking()
.ToListAsync();
O comportamento de acompanhamento padrão pode ser alterado no nível da instância de contexto:
context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
var blogs = await context.Blogs.ToListAsync();
A próxima seção explica quando uma consulta sem acompanhamento pode ser menos eficiente do que uma consulta de acompanhamento.
Resolução de identidade
Como uma consulta de acompanhamento usa o rastreador de alterações, o EF Core faz a resolução de identidade em uma consulta de acompanhamento. Ao materializar uma entidade, o EF Core retornará a mesma instância de entidade do rastreador de mudanças se ela já estiver sendo acompanhada. Se o resultado contiver a mesma entidade várias vezes, a mesma instância será retornada para cada ocorrência. Consultas sem acompanhamento:
- Não use o rastreador de alterações e não faça a resolução de identidade.
- Retorne uma nova instância da entidade mesmo quando a mesma entidade estiver contida no resultado várias vezes.
O acompanhamento e o não acompanhamento podem ser combinados na mesma consulta. Ou seja, você pode ter uma consulta sem rastreamento, que realiza a resolução de identidade nos resultados. Assim como AsNoTracking o operador que pode ser consultado, adicionamos outro operador AsNoTrackingWithIdentityResolution<TEntity>(IQueryable<TEntity>). Também há uma entrada associada adicionada na QueryTrackingBehavior enumeração. Quando a consulta para usar a resolução de identidade é configurada sem rastreamento, um rastreador de alterações autônomo é usado em segundo plano ao gerar os resultados da consulta, para que cada instância seja materializada apenas uma vez. Como esse rastreador de alterações é diferente do que está no contexto, os resultados não são acompanhados pelo contexto. Depois que a consulta é totalmente enumerada, o rastreador de alterações sai do escopo e é coletado pelo coletor de lixo conforme necessário.
var blogs = await context.Blogs
.AsNoTrackingWithIdentityResolution()
.ToListAsync();
Configurando o comportamento de acompanhamento padrão
Se você se encontrar alterando o comportamento de acompanhamento para muitas consultas, talvez queira alterar o padrão em vez disso:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder
.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFQuerying.Tracking;Trusted_Connection=True;ConnectRetryCount=0")
.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking);
}
Isso torna todas as consultas sem acompanhamento por padrão. Você ainda pode adicionar AsTracking para fazer acompanhamento de consultas específicas.
Acompanhamento e projeções personalizadas
Mesmo que o tipo de resultado da consulta não seja um tipo de entidade, o EF Core ainda acompanhará os tipos de entidade contidos no resultado por padrão. Na consulta a seguir, que retorna um tipo anônimo, as instâncias de Blog
no conjunto de resultados serão monitoradas.
var blog = context.Blogs
.Select(
b =>
new { Blog = b, PostCount = b.Posts.Count() });
Se o conjunto de resultados contiver tipos de entidade saindo da composição LINQ, o EF Core os acompanhará.
var blog = context.Blogs
.Select(
b =>
new { Blog = b, Post = b.Posts.OrderBy(p => p.Rating).LastOrDefault() });
Se o conjunto de resultados não contiver nenhum tipo de entidade, nenhum acompanhamento será feito. Na consulta a seguir, retornamos um tipo anônimo com alguns dos valores da entidade (mas nenhuma instância do tipo de entidade real). Não há entidades rastreadas resultantes da consulta.
var blog = context.Blogs
.Select(
b =>
new { Id = b.BlogId, b.Url });
O EF Core dá suporte à avaliação do cliente na projeção de nível superior. Se o EF Core materializar uma instância de entidade para avaliação do cliente, ela será controlada. Aqui, como estamos passando entidades blog
para o método cliente StandardizeURL
, o EF Core também acompanhará as instâncias do blog.
var blogs = await context.Blogs
.OrderByDescending(blog => blog.Rating)
.Select(
blog => new { Id = blog.BlogId, Url = StandardizeUrl(blog) })
.ToListAsync();
public static string StandardizeUrl(Blog blog)
{
var url = blog.Url.ToLower();
if (!url.StartsWith("http://"))
{
url = string.Concat("http://", url);
}
return url;
}
O EF Core não rastreia as instâncias de entidade sem chave contidas no resultado. Mas o EF Core rastreia todas as outras instâncias dos tipos de entidades com uma chave conforme as regras mencionadas acima.
Versões anteriores
Antes da versão 3.0, o EF Core tinha algumas diferenças na forma como o acompanhamento era feito. Diferenças notáveis são as seguintes:
Conforme explicado na página Avaliação do Cliente versus Servidor , o EF Core dá suporte à avaliação do cliente em qualquer parte da consulta antes da versão 3.0. A avaliação do cliente causou a materialização das entidades, que não eram parte do resultado. Portanto, o EF Core analisou o resultado para detectar o que rastrear. Esse design tinha certas diferenças da seguinte maneira:
A análise do cliente na projeção, que causou materialização, mas não retornou a instância da entidade materializada, não foi rastreada. O exemplo a seguir não rastreou
blog
entidades.var blogs = await context.Blogs .OrderByDescending(blog => blog.Rating) .Select( blog => new { Id = blog.BlogId, Url = StandardizeUrl(blog) }) .ToListAsync();
O EF Core não rastreou os objetos que saem da composição LINQ em determinados casos. O exemplo a seguir não rastreou
Post
.var blog = context.Blogs .Select( b => new { Blog = b, Post = b.Posts.OrderBy(p => p.Rating).LastOrDefault() });
Sempre que os resultados da consulta continham entidades sem chave, a consulta inteira não era rastreada. Isso significa que os tipos de entidade com chaves, que estão no resultado, também não estavam sendo rastreados.
O EF Core costumava realizar a resolução de identidade em consultas sem acompanhamento. Ele usou referências fracas para acompanhar entidades que já haviam sido retornadas. Portanto, se um conjunto de resultados contivesse a mesma entidade várias vezes, você obteria a mesma instância para cada ocorrência. No entanto, se um resultado anterior com a mesma identidade saiu do escopo e foi recolhido como lixo, uma nova instância foi retornada pelo EF Core.