也许我误解了DbContext
和DbSet
所做的缓存,但我的印象是有一些缓存会持续下去。当我运行以下代码时,我看到了我不会期望的行为:
var ctx = CreateAContext();
var sampleEntityId = ctx.SampleEntities.Select(i => i.Id)
.Single(i => i == 3); //Calls DB as expected
var cachedEntityId = ctx.SampleEntities.Select(i => i.Id)
.Single(i => i == 3); //Calls DB unexpectedly
这里发生了什么?我认为你从DbSet
获得的部分内容是它首先检查本地缓存,以便在查询数据库之前查看该对象是否存在。我在这里缺少某种配置选项吗?
答案 0 :(得分:39)
.Find
是什么@emcas88 is trying to say只有在DbSet
上使用.Single
方法时,EF才会检查缓存。
除非您使用的是二级缓存,否则使用.First
,.Where
,{{1}}等不会缓存结果。
答案 1 :(得分:28)
这是因为伸展方法的实现,使用了上下文的Find方法
contextName.YourTableName.Find()
首先验证缓存。希望它有所帮助。
答案 2 :(得分:22)
有时我会使用我的扩展方法:
using System.Linq;
using System.Linq.Expressions;
namespace System.Data.Entity
{
public static class DbSetExtensions
{
public static TEntity FirstOrDefaultCache<TEntity>(this DbSet<TEntity> queryable, Expression<Func<TEntity, bool>> condition)
where TEntity : class
{
return queryable
.Local.FirstOrDefault(condition.Compile()) // find in local cache
?? queryable.FirstOrDefault(condition); // if local cache returns null check the db
}
}
}
用法:
db.Invoices.FirstOrDefaultCache(x => x.CustomerName == "Some name");
您也可以将SingleOrDefault替换为SingleOrDetfault。
答案 3 :(得分:11)
看看EF Docs,你会在那里找到答案:
请注意,DbSet和IDbSet始终会针对数据库创建查询 并且将始终涉及到数据库的往返,即使 返回的实体已存在于上下文中。执行查询 在以下情况下对数据库:
- 它由 foreach (C#)或 For Each (Visual Basic)语句枚举。
- 它由
ToArray
,ToDictionary
或ToList
等集合操作枚举。First
或Any
等LINQ运算符在查询的最外部指定。- 调用以下方法:
Load
,DbSet
和DbEntityEntry.Reload
上的Database.ExecuteSqlCommand
扩展方法。
答案 4 :(得分:7)
EF6不会执行缓存ootb的结果。要缓存结果,您需要使用二级缓存。在CodePlex上看到这个有前景的项目:
Second Level Caching for EF 6.1
请记住,如果数据库中的数据发生更改,您将无法立即了解它。有时这取决于项目很重要。 ;)
答案 5 :(得分:-1)
在MSDN上非常清楚。 请注意找到的内容
[https://docs.microsoft.com/en-us/ef/ef6/querying/][1]
using (var context = new BloggingContext())
{
// Will hit the database
var blog = context.Blogs.Find(3);
// Will return the same instance without hitting the database
var blogAgain = context.Blogs.Find(3);
context.Blogs.Add(new Blog { Id = -1 });
// Will find the new blog even though it does not exist in the database
var newBlog = context.Blogs.Find(-1);
// Will find a User which has a string primary key
var user = context.Users.Find("johndoe1987");
}