前言

今天没有废话了,直接看代码

非跟踪查询

跟踪行为决定了 Entity Framework Core 是否将有关实体实例的信息保留在其更改跟踪器中。 如果已跟踪某个实体,则该实体中检测到的任何更改都会在 SaveChanges() 期间永久保存到数据库。 EF Core 还将修复跟踪查询结果中的实体与更改跟踪器中的实体之间的导航属性

看代码

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

在只读方案中使用结果时,非跟踪查询十分有用。 可以更快速地执行非跟踪查询,因为无需设置更改跟踪信息。 如果不需要更新从数据库中检索到的实体,则应使用非跟踪查询。 可以将单个查询替换为非跟踪查询。

应用:进行只读查询时,例如进行数据的筛选时

跟踪查询

返回实体类型的查询是默认会被跟踪的。 这表示可以更改这些实体实例,然后通过 SaveChanges() 持久化这些更改。 在以下示例中,将检测到对博客评分所做的更改,并在 SaveChanges() 期间将这些更改持久化到数据库中。

var blog = context.Blogs.SingleOrDefault(b => b.BlogId == 1);
blog.Rating = 5;
context.SaveChanges();

应用场景:我们利用EF CORE进行常规查询时操作,通常都不设置为AsNoTracking(),因为通常我们查改是一起的,有一个post就会通常对应一个GET。

由于跟踪查询使用更改跟踪器,因此 EF Core 将在跟踪查询中执行标识解析。 当具体化实体时,如果 EF Core 已被跟踪,则会从更改跟踪器返回相同的实体实例。 如果结果中多次包含相同的实体,则每次会返回相同的实例。 非跟踪查询不会使用更改跟踪器,也不会执行标识解析。 因此会返回实体的新实例,即使结果中多次包含相同的实体也是如此。

什么时候跟踪?

即使查询的结果类型不是实体类型,默认情况下 EF Core 也会跟踪结果中包含的实体类型。 在以下返回匿名类型的查询中,结果集中的 Blog 实例会被跟踪。

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

 

如果结果集包含来自 LINQ 组合的实体类型,EF Core 将跟踪它们。

var blog = context.Blogs
    .Select(b =>
        new
        {
            Blog = b,
            Post = b.Posts.OrderBy(p => p.Rating).LastOrDefault()
        });

如果结果集不包含任何实体类型,则不会执行跟踪。 在以下查询中,我们返回匿名类型(具有实体中的某些值,但没有实际实体类型的实例)。 查询中没有任何被跟踪的实体。

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

总结:当返回类型为实体或者返回值中包含实体类型,EFCORE 都会默认进行跟踪。

 

参考文献:https://docs.microsoft.com/zh-cn/ef/core/querying/tracking