过去我们常常使用Where或First(FirstOrDefault)方法来查找对应的实体,比如:
- var query = context.CertInfoMakeDetails.ToList().Where(make => int.Parse(make.CertCode) >= startcode &&
- int.Parse(make.CertCode) <=
- (startcode + count - 1) &&
- make.ProductName == productName);
var query = context.CertInfoMakeDetails.ToList().Where(make => int.Parse(make.CertCode) >= startcode && int.Parse(make.CertCode) <= (startcode + count - 1) && make.ProductName == productName);
这样做的缺点是:即使我们相应的实体已经被DbContext缓存,EF还是会去执行数据库访问,而数据库访问是被普遍认为比较耗费性能的。
从EF4.1开始,微软为我们提供了一个新的API:DbSet<>.Find(),它可以帮助我们通过主键来查找对应的实体。并且如果相应的实体已经被DbContext缓存,EF会在缓存中直接返回对应的实体,而不会执行数据库访问。
比如我们查找证书ID为"101"的实体:
- var query = context.CertInfoMakeDetails.Find("101");
var query = context.CertInfoMakeDetails.Find("101");
也可以使用联合主键(比如查找CertCode = "101", ProductName = "ABC")的实体:
- var query = context.CertInfoMakeDetails.Find("101", "ABC");
var query = context.CertInfoMakeDetails.Find("101", "ABC");
注意:此处输入联合主键的次序需要按照我们定义改实体类时声明主键的次序。
和之前使用Where或First调用不同,Find也可以找到刚刚新增的实体:
- using (var context = new MyContext())
- {
- context.CertInfoMakeDetails.Add(new CertInfoMakeDetail {....});
- var newOne = context.Find(“Id”);
- }
using (var context = new MyContext()) { context.CertInfoMakeDetails.Add(new CertInfoMakeDetail {....}); var newOne = context.Find(“Id”); }
最后让我们来看看Find是如何实现的:
- public TEntity Find(params object[] keyValues)
- {
- this.InternalContext.ObjectContext.AsyncMonitor.EnsureNotEntered();
- this.InternalContext.DetectChanges(false);
- WrappedEntityKey key = new WrappedEntityKey(this.EntitySet, this.EntitySetName, keyValues, "keyValues");
- object obj2 = this.FindInStateManager(key) ?? this.FindInStore(key, "keyValues");
- if ((obj2 != null) && !(obj2 is TEntity))
- {
- throw System.Data.Entity.Resources.Error.DbSet_WrongEntityTypeFound(obj2.GetType().Name, typeof(TEntity).Name);
- }
- return (TEntity) obj2;
- }
public TEntity Find(params object[] keyValues) { this.InternalContext.ObjectContext.AsyncMonitor.EnsureNotEntered(); this.InternalContext.DetectChanges(false); WrappedEntityKey key = new WrappedEntityKey(this.EntitySet, this.EntitySetName, keyValues, "keyValues"); object obj2 = this.FindInStateManager(key) ?? this.FindInStore(key, "keyValues"); if ((obj2 != null) && !(obj2 is TEntity)) { throw System.Data.Entity.Resources.Error.DbSet_WrongEntityTypeFound(obj2.GetType().Name, typeof(TEntity).Name); } return (TEntity) obj2; }
首先,EF调用了EnsureNotEntered() 方法来检查内部ObjectContext的状态,如果这个实例当前获得了一个排它锁,那么就抛出异常。之后调用DetectChanges 方法来同步了对象状态。WrappedEntityKey 主要用来将Find函数的参数包装成一个KeyValuePair。
之后,Find 方法首先调用 FindInStateManager 方法在缓存中进行查找,如果找不到对应的实体,那么就调用 FindInStore 在对数据库进行查找,如果仍然找不到,就抛出异常,否则返回对应实体。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
2007-03-29 今天你多态了吗?(一篇被转烂的文章,不在乎我再转一次)
2007-03-29 用C#获取系统有关环境、属性(转)