Entity Framework Code First: Get Entities From Local Cache or the Database

Entity Framework Code First makes it very easy to access local (first level) cache: you just access the DbSet<T>.Local property. This way, no query is sent to the database, only performed in already loaded entities.

If you want to first search local cache, then the database, if no entries are found, you can use this extension method:

   1: public static class DbContextExtensions
   2: {
   3:     public static IQueryable<T> LocalOrDatabase<T>(this DbContext context, Expression<Func<T, Boolean>> expression) where T : class
   4:     {
   5:         IEnumerable<T> localResults = context.Set<T>().Local.Where(expression.Compile());
   6:  
   7:         if (localResults.Any() == true)
   8:         {
   9:             return (localResults.AsQueryable());
  10:         }
  11:  
  12:         IQueryable<T> databaseResults = context.Set<T>().Where(expression);
  13:  
  14:         return (databaseResults);
  15:     }
  16: }

                             

6 Comments

  • nice. I'll try to use it.

  • It would be nice if you could cache the manually compiled expressions to avoid that expense each time. Just not sure if GetHashCode on Expression would be sufficient or if we'd have to pay a hefty reflection price each time just to build up enough of a hash key to identify the expression (thereby rendering the point moot).

  • @brianhartung:
    Yes, I think it can be done, by introducing a static readonly ConcurrentDictionary field.

  • @brianhartung:

    You're right - expressions use reference equality, so in your example the two expressions are not considered equal.

    If you're just looking to retrieve the entity by its primary key, you might want to look at the Find method introduced in 4.1:

    "If an entity with the given primary key values exists in the context, then it is returned immediately without making a request to the store. Otherwise, a request is made to the store for an entity with the given primary key values and this entity, if found, is attached to the context and returned. If no entity is found in the context or the store, then null is returned."

    var customer1 = context.Customers.Find(1);
    var customer2 = context.Customers.Find(1);

    http://blogs.msdn.com/b/adonet/archive/2011/01/28/using-dbcontext-in-ef-feature-ctp5-part-3-finding-entities.aspx

  • Hi Richard...yep, I am familiar with the Find method...I was just using the first simple predicate that came to mind. So I suppose the larger question is if we can find a way to perform transparent second-level caching of compiled expressions that would avoid paying the (relatively speaking) heavy cost of compilation (that we're trying to avoid in the first place) just to do the lookup in our cache structure.

    Cheers,
    -Brian

  • Not sure why I didn't spend the 30 seconds to look on StackOverflow for this in the first place... :)

    http://stackoverflow.com/questions/258864/when-an-expressiont-is-compiled-is-it-implicitly-cached

Comments have been disabled for this content.