Perché Entity Framework 6.x non memorizza i risultati nella cache?

Forse sto fraintendendo il caching di DbContext e DbSet , ma ho avuto l’impressione che ci fosse un caching che andava avanti. Sto vedendo un comportamento che non mi aspetterei quando eseguo il seguente codice:

 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 

Cosa sta succedendo qui? Ho pensato che parte di ciò che ottieni da DbSet è che prima controllerebbe la cache locale per vedere se quell’object esiste prima di interrogare il database. C’è solo una sorta di opzione di configurazione che mi manca qui?

Quello che @ emcas88 sta cercando di dire è che EF controllerà solo la cache quando si usa il metodo DbSet su DbSet .

Utilizzando .Single , .First , .Where , etc non memorizzerà i risultati nella cache a meno che non si stia utilizzando il caching di secondo livello.

Questo perché l’implementazione dei metodi estensori usa il metodo Find del contesto

 contextName.YourTableName.Find() 

per verificare prima la cache. Spero che sia d’aiuto.

A volte uso il mio metodo di estensione:

 using System.Linq; using System.Linq.Expressions; namespace System.Data.Entity { public static class DbSetExtensions { public static TEntity FirstOrDefaultCache(this DbSet queryable, Expression> 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 } } } 

Uso:

 db.Invoices.FirstOrDefaultCache(x => x.CustomerName == "Some name"); 

È anche ansible sostituire FirstOrDefault con SingleOrDetfault.

Dai un’occhiata a EF Docs , troverai la risposta qui:

Si noti che DbSet e IDbSet creano sempre query sul database e implicano sempre un ritorno al database anche se le entity framework restituite esistono già nel contesto. Una query viene eseguita sul database quando:

  • È enumerato da un’istruzione foreach (C #) o For Each (Visual Basic).
  • È elencato da un’operazione di raccolta come ToArray , ToDictionary o ToList .
  • Gli operatori LINQ come First o Any sono specificati nella parte più esterna della query.
  • I seguenti metodi sono chiamati: il metodo di estensione Load su un DbSet , DbEntityEntry.Reload e Database.ExecuteSqlCommand .

EF6 non produce risultati in cache ootb. Per memorizzare i risultati nella cache, è necessario utilizzare una cache di secondo livello. Guarda questo promettente progetto su CodePlex:

Caching di secondo livello per EF 6.1

Tieni presente che se i dati cambiano sul db, non lo saprai immediatamente. A volte questo è importante a seconda del progetto. 😉