前言

最近将RabbitMQ正式封装引入到.NET Core 2.0项目当中,之前从未接触过这个高大上的东东跟着老大学习中,其中收获不少,本打算再看看RabbitMQ有时间写写,回来后和何镇汐大哥探讨了一点关于EF和EF Core的内容,于是乎本文就出来了。EF 6.x和EF Core中的查询缓存想必大家都有耳闻或者了解,从数据库中查询出来的实体会形成快照在内存中Copy一份且被上下文跟踪,接下来我们要讲的内容就是这个,我们来看看。

EF 6.x和EF Core查询缓存思考

首先我利用EF Core通过一个例子来进入今天的主题,在此过程中您也可多一点思考空间并对照和您想象中的结果是否有出入或者不一致的地方。

var context = new EFCoreDbContext();

var blog1 = context.Blogs.Find(3);

Console.WriteLine($"数据库原始值为{blog1.Name}");

blog1.Name = "Jeffcky";

var blog2 = context.Blogs.FirstOrDefault(d => d.Id == 3);

Console.WriteLine($"查询数据库后的值为{blog2.Name}"

上述我们通过Find方法查询出Blog1,然后对Name进行赋值,紧接着我们再次查询主键等于3的实体,您猜想一下blog2中的Name会等于多少呢?

我们看看如上图所示结果为Jeffcky,有的童鞋就问了,我们进行第一次查询时值为3,然后我们仅仅只是赋值为Jeffcky并未提交,当我们再次查询相同实体时结果却为Jeffcky呢?难道不应该是3么,对吧。稍微对EF或者EF Core有所了解的大佬们明白第一次查询时会有快照,当下次查询时EF或者EF Core会在内存中根据第一次查询所对应的哈希值和主键去查找,此时查找到则直接利用内存中的对象,所以此时blog2的Name为Jeffcky。问题是不是到此就结束了呢?如果是这样,那我大半夜还浪费这时间写这篇博客!接下来我们再来看看两次查询所生成的SQL如何?

在EF 6.x和EF Core中 通过Find方法基于主键查询查询可重用,什么意思呢?如上第一个查询采用参数化查询,也就说如果我们下次再利用Find方法查询那么将不会到数据库查询,而是直接从内存中返回,有的童鞋就想了,恩,挺好,这样显著提高了查询性能,我只能说不一定看对应场景,如果对于非常频繁的查询我个人觉得不建议用此方法,因为还有对实体的更新操作啊,此时数据更新了却在内存中的值没有更新显示到UI上也就是说是过期了值,那么您觉得这个时候用Find方法还可取吗。对于第二个查询则直接采取赋值的形式(在我即将出版的《你必须掌握的EntityFramework 6.x和Core 2.0》书中有讲解EF 6.x查询的很大问题)这都不是事,问题是第二次我们利用FirstOrDefault方法查询此时居然走数据库了,不信,您可以看看如下利用SQL Profiler监控得到的SQL语句。

这就让人有点费解了,第二个查询既然是到数据库中查询那为何我们得到的值当前第一次查询出来修改但未被提交的值呢?这不是自相矛盾么,EF Core这样设计的意义何在,我也想不通,我能想到的是在同一上下文中大部分情况下不会对同一实体查询多次,但是谁能保证呢。 在EF Core中除了Find会进行翻译缓存,其他比如First、FirstOrDefault、Last、LastOrDefault都会到数据库中查询,当我们利用Last或者LastOrDefault查询时会出现更有意思的事情,我们看看生成的SQL语句:

var blog3 = context.Blogs.Last();

EF Core大哥哥们这么简单的查询问题都没测试到么,你翻译给我让我误以为这是返回所有列表了,结果一看查询出来的值却是对的,我想这是EF Core大哥哥们忘记加上TOP 1和ORDER BY了,到github上一搜索原来有大神提过这个ISSUE(https://github.com/aspnet/EntityFrameworkCore/issues/10493)在2.1版本发布会解决这个问题。好了我们回到主题所遇到的问题,在同一上下文查询同一实体,第一次查询如果我们利用Find方法查询会进行翻译缓存,待下一次再次查询时不会到数据库中查询,如果是下一次查询不是利用Find方法查询,比如FirstOrDefault此时会到数据库中查询但是此时的值却不是数据库中的值而是当前被修改而未被提交的值,那么我们如何获取数据库中的值而不是当前修改而未被提交的值呢?请往下看。

EF和EF Core获取数据库值而不是当前修改未被提交的值

我们讨论了问题的出现,接下来我们尝试利用方法来解决,我们可以对上下文所跟踪的实体进行移除通过Local.Remove,如下:

var context = new EFCoreDbContext();

var blog1 = context.Blogs.Find(3);

Console.WriteLine($"数据库原始值为{blog1.Name}");

blog1.Name = "Jeffcky";

context.Blogs.Local.Remove(blog1);

var blog2 = context.Blogs.FirstOrDefault(d => d.Id == 3);

Console.WriteLine($"查询数据库后的值为{blog2.Name}");

Local方法意味获取在本地所添加、修改等的实体,我们获取被上下文所本地被上下文所跟踪的实体然后移除,继而再进行查询是不是就可以移除呢?不好意思移除不了。

利用AsNoTracking方法

这个算是最简单的方法之一了,仅仅对于查询而言通过此方法不会形成快照从而提高查询性能。

var context = new EFCoreDbContext();

var blog1 = context.Blogs.Find(3);

Console.WriteLine($"数据库原始值为{blog1.Name}");

blog1.Name = "Jeffcky";

var blog2 = context.Blogs.AsNoTracking().FirstOrDefault(d => d.Id == 3);

Console.WriteLine($"查询数据库后的值为{blog2.Name}");

将实体状态标记为Detached不被上下文跟踪

var context = new EFCoreDbContext();

var blog1 = context.Blogs.Find(3);

Console.WriteLine($"数据库原始值为{blog1.Name}");

blog1.Name = "Jeffcky";

context.Entry(blog1).State = EntityState.Detached;

var blog2 = context.Blogs.FirstOrDefault(d => d.Id == 3);

Console.WriteLine($"查询数据库后的值为{blog2.Name}");

通过Reload方法刷新实体

var context = new EFCoreDbContext();

var blog1 = context.Blogs.Find(3);

Console.WriteLine($"数据库原始值为{blog1.Name}");

blog1.Name = "Jeffcky";

context.Entry(blog1).Reload();

var blog2 = context.Blogs.FirstOrDefault(d => d.Id == 3);

Console.WriteLine($"查询数据库后的值为{blog2.Name}");

通过GetDatabaseValues方法直接获取数据库中值

var context = new EFCoreDbContext();

var blog1 = context.Blogs.Find(3);

Console.WriteLine($"数据库原始值为{blog1.Name}");

blog1.Name = "Jeffcky";

var blog2 = (Blog)context.Entry(blog1).GetDatabaseValues().ToObject();

Console.WriteLine(blog2.Name);

//或者

var db = context.Entry(blog1).GetDatabaseValues();

Console.WriteLine(db["Name"]);

总结

好了今天的内容就到此为止了,无论是EF 6.x还是EF Core,只要我们对一些原理足够了解才不至于出现让人意想不到的问题。希望本文对您有所帮助,下节开始讲讲RabbitMQ,我们下节再会。

原文地址:https://www.cnblogs.com/CreateMyself/p/8965216.html


.NET社区新闻,深度好文,欢迎访问公众号文章汇总 http://www.csharpkit.com

讨论过后而引发对EF 6.x和EF Core查询缓存的思考相关推荐

  1. 给 EF Core 查询增加 With NoLock

    给 EF Core 查询增加 With NoLock Intro EF Core 在 3.x 版本中增加了 Interceptor,使得我们可以在发生低级别数据库操作时作为 EF Core 正常运行的 ...

  2. ef 多个左联接查询_.NET 云原生架构师训练营(模块二 基础巩固 EF Core 查询)--学习笔记...

    2.4.5 EF Core -- 查询 关联数据加载 客户端与服务端运算 跟踪与不跟踪 复杂查询运算 原生 SQL 查询 全局查询筛选器 关联数据加载 学员和助教都在项目分组中,调整模型,删除 Ass ...

  3. .NET 云原生架构师训练营(模块二 基础巩固 EF Core 查询)--学习笔记

    2.4.5 EF Core -- 查询 关联数据加载 客户端与服务端运算 跟踪与不跟踪 复杂查询运算 原生 SQL 查询 全局查询筛选器 关联数据加载 学员和助教都在项目分组中,调整模型,删除 Ass ...

  4. ps -ef 两个pid_ps -ef 与 aux

    Linux下显示系统进程的命令ps,最常用的有ps -ef 和ps aux.这两个到底有什么区别呢?两者没太大差别,讨论这个问题,要追溯到Unix系统中的两种风格,System V风格和BSD 风格, ...

  5. 使用Ef框架进行分页..EF模糊查询..EF多表内连接查询

    先来DAL层代码..稍后解释... public List<Staff> Getstaff(string DepId,string staffname,DateTime date ,int ...

  6. c ef框架-mysql_.net EF框架 MySql實現實例

    1.nuget中添加包EF和MySql.Data.Entity 2.config文件添加如下配置 1.配置entitframework節點(一般安裝EF時自動添加) 2.配置system.data節點 ...

  7. ef mysql自动更新_EF Core中怎么实现自动更新实体的属性值到数据库

    我们在开发系统的时候,经常会遇到这种需求数据库表中的行被更新时需要自动更新某些列. 数据库 比如下面的Person表有一列UpdateTime,这列数据要求在行被更新后自动更新为系统的当前时间. Pe ...

  8. ef mysql code first_[EF]vs15+ef6+mysql code first方式

    写在前面 前面有篇文章,尝试了db first方式,但不知道是什么原因一直没有成功,到最后也没解决,今天就尝试下code first的方式. 一个例子 步骤 Connector/Net 下载该文件,并 ...

  9. ef mysql modelfirst_Entity Framework(EF的Model First方法)

    EntityFramework,是Microsoft的一款ORM(Object-Relation-Mapping)框架.同其它ORM(如,NHibernate,Hibernate)一样, 一是为了使开 ...

最新文章

  1. 七天学会NodeJS
  2. GPT-3英文版的接口
  3. magento获取判断当前页或句柄handles
  4. python小程序-python学习—几个简单小程序
  5. 说一说MVC的CompressActionFilterAttrubute(五)
  6. 蓝牙耳机和蓝牙鼠标相互干扰_蓝牙耳机推荐:编辑亲测后中肯评价五大爆款蓝牙耳机...
  7. java socket 一边关闭_java socket - 半关闭
  8. python的智能算法_scikit-opt——Python中的群体智能优化算法库
  9. win7下搭建小程序服务器,技术开发人员告诉你微信小程序怎么做
  10. Node出错导致运行崩溃的解决方案
  11. Linux脚本验证的常见方法,linux shell常用循环与判断语句(for,while,until,if)使用方法...
  12. CodeVs天梯青铜Bronze题解
  13. lecture7-序列模型及递归神经网络RNN
  14. webpack路径问题总结
  15. python与分形0011 - 【教程】带辐条的多边形
  16. S2B2B-云分销系统介绍
  17. 安卓变苹果12系统永久,安卓系统变苹果系统2020
  18. 抖音高贵气质的签名_抖音2100万赞!95后小伙“乡村维密秀”走红外媒:人生道阻且长,有梦想,谁都了不起...
  19. semi-suppervised learning 半监督学习
  20. 记一篇IT培训日记061-班活动

热门文章

  1. vue vue-router vuex element-ui axios 写一个代理平台的学习笔记(十一)构思商品页面...
  2. C# 操作FireBird 附源码
  3. 08 comet反向ajax
  4. 我的邮局系统,欢迎大家注册!hotxf.com
  5. 有奖问题征集|向大咖Scott 发问,好礼等你领!
  6. 通过Dapr实现一个简单的基于.net的微服务电商系统(十二)——istio+dapr构建多运行时服务网格...
  7. EFCore 5 新特性 Savepoints
  8. 企业级精致 Blazor 套件 BootstrapBlazor 介绍
  9. FreeSql接入CAP的实践
  10. 使用 C# sdk 连接 高可用的 rabbitmq 镜像集群