Perhaps I am misunderstanding the caching that DbContext
and DbSet
does but I was under the impression that there was some caching that would go on. I'm seeing behavior that I wouldn't expect when I run the following code:
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
What's going on here? I thought that part of what you get from DbSet
is that it would first check the local cache to see if that object exists before querying the database. Is there just some sort of configuration option I am missing here?
What @emcas88 is trying to say is that EF will only check the cache when you use the .Find
method on DbSet
.
Using .Single
, .First
, .Where
, etc will not cache the results unless you are using second-level caching.
This is because the implementation of the extensor methods, use the Find method of the context
contextName.YourTableName.Find()
to verify first the cache. Hope it helps.
Sometimes I use my extension method:
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
}
}
}
Usage:
db.Invoices.FirstOrDefaultCache(x => x.CustomerName == "Some name");
You can replace FirstOrDefault with SingleOrDetfault also.
Take a look at EF Docs, you will find answer there:
Note that DbSet and IDbSet always create queries against the database
and will always involve a round trip to the database even if the
entities returned already exist in the context. A query is executed
against the database when:
- It is enumerated by a foreach (C#) or For Each (Visual Basic) statement.
- It is enumerated by a collection operation such as
ToArray
, ToDictionary
, or ToList
.
- LINQ operators such as
First
or Any
are specified in the outermost part of the query.
- The following methods are called: the
Load
extension method on a DbSet
, DbEntityEntry.Reload
, and Database.ExecuteSqlCommand
.
EF6 doesn't do results caching ootb. In order to cache results, you need to use a second level cache. See this promising project on CodePlex:
Second Level Caching for EF 6.1
Keep in mind that if data changes on the db, you won't immediately know about it. Sometimes this is important depending upon the project. ;)
It is very clear on MSDN.
Please note what is find
[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");
}