Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update tracking.md #4298

Merged
merged 9 commits into from
Apr 5, 2023
24 changes: 14 additions & 10 deletions entity-framework/core/querying/tracking.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,37 +7,41 @@ uid: core/querying/tracking
---
# Tracking vs. No-Tracking Queries

Tracking behavior controls if Entity Framework Core will keep information about an entity instance in its change tracker. If an entity is tracked, any changes detected in the entity will be persisted to the database during `SaveChanges()`. EF Core will also fix up navigation properties between the entities in a tracking query result and the entities that are in the change tracker.
Tracking behavior controls if Entity Framework Core keeps information about an entity instance in its change tracker. If an entity is tracked, any changes detected in the entity are persisted to the database during `SaveChanges`. EF Core also fixes up navigation properties between the entities in a tracking query result and the entities that are in the change tracker.

> [!NOTE]
> [Keyless entity types](xref:core/modeling/keyless-entity-types) are never tracked. Wherever this article mentions entity types, it refers to entity types which have a key defined.

> [!TIP]
> You can view this article's [sample](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Querying/Tracking) on GitHub.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why this change?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMAO, too much bling can be distracting. I can revert.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, please.

You can view this article's [sample](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Querying/Tracking) on GitHub.
Rick-Anderson marked this conversation as resolved.
Show resolved Hide resolved

## Tracking queries

By default, queries that return entity types are tracking. Which means you can make changes to those entity instances and have those changes persisted by `SaveChanges()`. In the following example, the change to the blogs rating will be detected and persisted to the database during `SaveChanges()`.
By default, queries that return entity types are tracking. A tracking query means any changes to entity instances are persisted by `SaveChanges`. In the following example, the change to the blogs rating is detected and persisted to the database during `SaveChanges`:

[!code-csharp[Main](../../../samples/core/Querying/Tracking/Program.cs#Tracking)]

When the results are returned in a tracking query, EF Core will check if the entity is already in the context. If EF Core finds an existing entity, then the same instance is returned. EF Core won't overwrite current and original values of the entity's properties in the entry with the database values. If the entity isn't found in the context, then EF Core will create a new entity instance and attach it to the context. Query results don't contain any entity which is added to the context but not yet saved to the database.
When the results are returned in a tracking query, EF Core checks if the entity is already in the context. If EF Core finds an existing entity, then the same instance is returned, which can potentially use less memory and be faster than a no-tracking query. EF Core doesn't overwrite current and original values of the entity's properties in the entry with the database values. If the entity isn't found in the context, EF Core creates a new entity instance and attaches it to the context. Query results don't contain any entity which is added to the context but not yet saved to the database.

## No-tracking queries

No tracking queries are useful when the results are used in a read-only scenario. They're quicker to execute because there's no need to set up the change tracking information. If you don't need to update the entities retrieved from the database, then a no-tracking query should be used. You can swap an individual query to be no-tracking. No tracking query will also give you results based on what is in the database disregarding any local changes or added entities.
No tracking queries are useful when the results are used in a read-only scenario. They're generally quicker to execute because there's no need to set up the change tracking information. If the entities retrieved from the database don't need to be updated, then a no-tracking query should be used. An individual query can be swapped to be no-tracking. A no-tracking query also give results based on what's in the database disregarding any local changes or added entities.
Rick-Anderson marked this conversation as resolved.
Show resolved Hide resolved

[!code-csharp[Main](../../../samples/core/Querying/Tracking/Program.cs#NoTracking)]

You can also change the default tracking behavior at the context instance level:
The default tracking behavior can be changed at the context instance level:

[!code-csharp[Main](../../../samples/core/Querying/Tracking/Program.cs#ContextDefaultTrackingBehavior)]

The next section explains when a no-tracking query might be less efficient than a tracking query.

## Identity resolution

Since a tracking query uses the change tracker, EF Core will do identity resolution in a tracking query. When materializing an entity, EF Core will return the same entity instance from the change tracker if it's already being tracked. If the result contains the same entity multiple times, you get back same instance for each occurrence. No-tracking queries don't use the change tracker and don't do identity resolution. So you get back a new instance of the entity even when the same entity is contained in the result multiple times.
Since a tracking query uses the change tracker, EF Core does identity resolution in a tracking query. When materializing an entity, EF Core returns the same entity instance from the change tracker if it's already being tracked. If the result contains the same entity multiple times, the same instance is returned for each occurrence. No-tracking queries:

* Don't use the change tracker and don't do identity resolution.
* Return a new instance of the entity even when the same entity is contained in the result multiple times.

You can combine both of the above behaviors in same query. That is, you can have a no tracking query, which will do identity resolution in the results. Just like `AsNoTracking()` queryable operator, we've added another operator `AsNoTrackingWithIdentityResolution()`. There's also associated entry added in the <xref:Microsoft.EntityFrameworkCore.QueryTrackingBehavior> enum. When you configure the query to use identity resolution with no tracking, we use a stand-alone change tracker in the background when generating query results so each instance is materialized only once. Since this change tracker is different from the one in the context, the results are not tracked by the context. After the query is enumerated fully, the change tracker goes out of scope and garbage collected as required.
Both of the tracking and no-tracking can be combined in the same query. That is, you can have a no-tracking query, which does identity resolution in the results. Just like `AsNoTracking` queryable operator, we've added another operator <xref:Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.AsNoTrackingWithIdentityResolution%60%601(System.Linq.IQueryable{%60%600})>. There's also associated entry added in the <xref:Microsoft.EntityFrameworkCore.QueryTrackingBehavior> enum. When the query to use identity resolution is configured with no tracking, a stand-alone change tracker is used in the background when generating query results so each instance is materialized only once. Since this change tracker is different from the one in the context, the results are not tracked by the context. After the query is enumerated fully, the change tracker goes out of scope and garbage collected as required.
Rick-Anderson marked this conversation as resolved.
Show resolved Hide resolved

[!code-csharp[Main](../../../samples/core/Querying/Tracking/Program.cs#NoTrackingWithIdentityResolution)]

Expand All @@ -47,7 +51,7 @@ If you find yourself changing the tracking behavior for many queries, you may wa

[!code-csharp[Main](../../../samples/core/Querying/Tracking/NonTrackingBloggingContext.cs?name=OnConfiguring&highlight=5)]

This makes all your queries non-tracking by default. You can still add `AsTracking()` to make specific queries tracking.
This makes all your queries no-tracking by default. You can still add `AsTracking()` to make specific queries tracking.
Rick-Anderson marked this conversation as resolved.
Show resolved Hide resolved

## Tracking and custom projections

Expand Down