1.查询生命周期

在进入正题时候,我们先来了解EF Core查询的生命周期。

1.1LINQ查询会由Entity Framework Core处理并生成给数据库提供程序可处理的表示形式(说白了就是生成给数据库可识别数据形式)。

●发送的查询结果(查询表示形式)会被缓存,以便每次执行查询时无需进行1.1中处理。

1.2查询结果(查询表示形式)会传递到数据库提供程序

●数据库提供程序会识别出查询的哪些部分可以在数据库中求值。
●查询的这些部分会转换为特定数据库的查询语言(例如,关系数据库的T-SQL)。
●一个或多个查询会发送到数据库并返回结果集(返回的是数据库中的值,而不是实体实例中的)。

1.3对于结果集中的每一项

1.3.1如果这是跟踪查询(后续会讲到),EF会检查数据是否表示已在上下文实例的更改跟踪器中的实体中。

●如果是,则会返回现有实体。
●如果不是,则会创建新实体、设置更改跟踪并返回该新实体。

1.3.2如果这是非跟踪查询(后续会讲到),EF会检查数据是否表示已在此查询的结果集中的实体中。

●如果是,则会返回现有实体。非跟踪查询使用弱引用跟踪已返回的实体。如果具有相同标识的上一个结果超出范围,并运行垃圾回收,则可能会获得新的实体实例。
●如果不是,则会创建新实体并返回该新实体。

1.4执行查询时

当调用LINQ运算符时,只会生成查询的内存中表示形式。当我们使用查询结果(查询表示形式)时才会发送到数据库。导致查询发送到数据库的最常见操作如下:
●在for循环中循环访问结果:

复制代码
var blogs = from b in _context.Blog          select new          {             b.BlogId,             b.Url          }; //触发数据库查询foreach(var blog in blogs) {     var id = blog.BlogId; }
复制代码

当我们执行完LINQ运算符的时候,从SQL Server Profiler监控里面可以看到,并没有执行的SQL语句,也就是说查询结果blogs并没有立即发送给数据库获取返回数据结果集。

而当我们调试进去for循环时候,SQL Server Profiler监控里面可以看到出现了执行SQL语句。也就是说这时候查询结果blogs才执行发送给数据库返回结果集。

●使用ToList、ToArray、Single、Count等运算符

复制代码
_context.Blog.ToList(); _context.Blog.ToArray(); _context.Blog.Count(); _context.Blog.Single(); _context.Blog.First();
复制代码

执行这种形式运算符也会立即发送到数据库获取结果集的。具体执行过程呈现,这里大伙自行测试吧。
●将查询结果数据绑定到UI

2.跟踪查询与非跟踪查询

在1小节生命周期里面我们有提及过跟踪与非跟踪查询,现在我们来了解下这两种查询区别。

2.1跟踪查询

返回实体类型的查询是默认会被跟踪的,这表示如果这些实体实例有更改行为,会通过SaveChanges()持久化将更改的值更新到数据库中,但是如果更改的值跟实体实例的值相同,则不会持久化提交数据到数据库,这就是跟踪查询。在以下示例中,将检测到对博客链接所做的更改,并在 SaveChanges() 期间将这些更改持久化到数据库中。

复制代码
//返回blog实体类型的查询是默认会被跟踪var blog = _context.Blog.SingleOrDefault(b => b.BlogId == 1); //检测对博客链接所做的更改blog.Url = "1"; //持久化保存到数据库中_context.SaveChanges();
复制代码

实体初始链接值是1,当我们点击Save按钮保存的时候,检测到对博客链接所做的更改值还是1的时候,并不会提交更改值到数据库中的。看看下图SQL Server Profiler监控就知道,并没有监控到对应有更新的T-SQL语句,也就是说并没有执行更新操作:

当我们再把链接值更改为2点击保存时候,EF Core检测到博客链接值已经从1更改为2,就会持久化保存到数据库中。

blog.Url = "2";

废话少说,直接上图: