追蹤與不追蹤的查詢Tracking vs. No-Tracking Queries

追蹤行為可控制 Entity Framework Core 是否將在其變更追蹤程式中保存有關實體執行個體的資訊。Tracking behavior controls whether or not Entity Framework Core will keep information about an entity instance in its change tracker. 如果追蹤實體,即會在 SaveChanges() 期間,將實體中偵測到的任何變更保存於資料庫。If an entity is tracked, any changes detected in the entity will be persisted to the database during SaveChanges(). Entity Framework Core 也將在從追蹤查詢中取得的實體,以及先前已載入至 DbContext 執行個體的實體之間修正導覽屬性。Entity Framework Core will also fix-up navigation properties between entities that are obtained from a tracking query and entities that were previously loaded into the DbContext instance.

提示

您可以在 GitHub 上檢視此文章的範例 (英文)。You can view this article's sample on GitHub.

追蹤查詢Tracking queries

預設會追蹤傳回實體類型的查詢。By default, queries that return entity types are tracking. 這表示您可以對那些實體執行個體進行變更,並透過 SaveChanges() 來保存那些變更。This means you can make changes to those entity instances and have those changes persisted by SaveChanges().

在下列範例中,將會偵測到對部落格評等的變更,並在 SaveChanges() 期間將其保存於資料庫。In the following example, the change to the blogs rating will be detected and persisted to the database during SaveChanges().

using (var context = new BloggingContext())
{
    var blog = context.Blogs.SingleOrDefault(b => b.BlogId == 1);
    blog.Rating = 5;
    context.SaveChanges();
}

無追蹤查詢No-tracking queries

如果要在唯讀案例中使用結果,則不追蹤的查詢很實用。No tracking queries are useful when the results are used in a read-only scenario. 它們會以更快的速度執行,因為不需要設定變更追蹤資訊。They are quicker to execute because there is no need to setup change tracking information.

您可以將個別查詢切換為不追蹤:You can swap an individual query to be no-tracking:

using (var context = new BloggingContext())
{
    var blogs = context.Blogs
        .AsNoTracking()
        .ToList();
}

您也可以在內容執行個體層級變更預設的追蹤行為:You can also change the default tracking behavior at the context instance level:

using (var context = new BloggingContext())
{
    context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;

    var blogs = context.Blogs.ToList();
}

注意

不追蹤的查詢仍會在執行查詢內執行識別解析。No tracking queries still perform identity resolution within the excuting query. 如果結果集多次包含同一個實體,則將針對結果集中的每個相符項目傳回實體類別的相同執行個體。If the result set contains the same entity multiple times, the same instance of the entity class will be returned for each occurrence in the result set. 不過,會使用弱式參考來持續追蹤已經傳回的實體。However, weak references are used to keep track of entities that have already been returned. 如果先前具有相同身分識別的結果超出範圍,且執行記憶體回收,您可能會得到新的實體執行個體。If a previous result with the same identity goes out of scope, and garbage collection runs, you may get a new entity instance. 如需詳細資訊,請參閱查詢的運作方式For more information, see How Query Works.

追蹤和預測Tracking and projections

即使查詢的結果類型不是實體類型,但若結果包含實體類型,預設仍將追蹤它們。Even if the result type of the query isn't an entity type, if the result contains entity types they will still be tracked by default. 下列查詢會傳回匿名類型,並且將在結果集中追蹤 Blog 的執行個體。In the following query, which returns an anonymous type, the instances of Blog in the result set will be tracked.

using (var context = new BloggingContext())
{
    var blog = context.Blogs
        .Select(b =>
            new
            {
                Blog = b,
                Posts = b.Posts.Count()
            });
}

如果結果集未包含任何實體類型,則不會執行追蹤。If the result set does not contain any entity types, then no tracking is performed. 下列查詢會傳回匿名類型,並具有一些來自實體的值 (但沒有實際實體類型的執行個體),但不會執行任何追蹤。In the following query, which returns an anonymous type with some of the values from the entity (but no instances of the actual entity type), there is no tracking performed.

using (var context = new BloggingContext())
{
    var blog = context.Blogs
        .Select(b =>
            new
            {
                Id = b.BlogId,
                Url = b.Url
            });
}