2013-04-05 8 views
39

Sono nuovo in Entity Framework.Entity Framework Caching Issue

Ho ottenuto alcuni valori nel mio database utilizzando EF. Ritorna perfettamente e i valori sono mostrati nelle etichette. Ma quando elimino tutti i valori nella mia tabella (senza usare EF), la query EF restituisce i miei vecchi valori. So che l'EF memorizza i valori nella cache e restituisce i dati memorizzati nella cache per le esecuzioni successive. È corretto?

Quindi, come posso risolvere il problema quando ho cancellato tutti i valori nel mio database, ma EF restituisce i vecchi valori?

Edit:

Ora ho usato datamodel.SaveChanges(). Ma ora restituisce gli stessi vecchi valori.

mia query di esempio è guardare come di seguito:

SchoolBriefcaseEntities datamodel = new SchoolBriefcaseEntities(); 
datamodel.SaveChanges(); 
List<Compliance> compliance=new List<Compliance>(); 
IList<ComplianceModel> complianceModel; 
if (HttpContext.Current.User.IsInRole("SuperAdmin")) 
{ 
    compliance = datamodel.Compliances.Where(c => c.School.DistrictId == districtId).ToList(); 
} 
+3

Hai chiamato '.SaveChanges();' sul tuo dbContext? Se non l'hai fatto, le entità non saranno rimosse .. – Rob

+0

Per favore Leggi la mia intera domanda. Non ho usato la cancellazione nel codice. Ho cancellato i valori direttamente nel database –

+0

E il tuo contesto? Apri il contesto quando ne hai bisogno e chiudilo non appena hai finito. (Potresti voler migliorare la tua domanda, non è affatto chiaro) –

risposta

25

Se si sa che i cambiamenti avvenuti al di fuori di EF e volete aggiornare il vostro ctxt per un'entità specifica, è possibile chiamare ObjectContext.Refresh

datamodel.Refresh(RefreshMode.StoreWins, orders); 

Se questo vi sembra che sarà un evento comune, si dovrebbe disabilitare la cache oggetto nelle query:

SchoolBriefcaseEntities datamodel = new SchoolBriefcaseEntities(); 
datamodel.tblCities.MergeOption = MergeOption.NoTracking; 

o per spegnere livello di oggetto cache per specifica entità,

Context.Set<Compliances>().AsNoTracking(); 
+3

.AsNoTracking() per me – nadav

+1

Se viene utilizzato AsNoTracking(), DBContext non tiene traccia delle modifiche alle Enetities. In tal caso, non sarà possibile modificare Entità e salvarle utilizzando dbContext.SaveChanges(). –

+1

http://codethug.com/2016/02/19/Entity-Framework-Cache-Busting/ –

20

EF non verrà caricato le modifiche a meno che non si ri interrogare il contesto. EF esegue una query su db e carica le mappe in oggetti, controlla le modifiche eseguite sugli oggetti e non sul database. EF non tiene traccia delle modifiche apportate direttamente al database e non verrà mai tracciata.

È stata caricata una lista, quella lista è la cache in memoria. Anche chiamando Salva modifiche non si aggiorna. Dovrai interrogare nuovamente il contesto, cioè creare una nuova lista.

Per visualizzare le modifiche Si dovrà eseguire seguente riga di una volta di più,

datamodel.Compliances.Where(c => c.School.DistrictId == districtId).ToList() 
25

Quando si utilizza EF è da carichi di default ogni entità solo una volta per contesto. La prima query crea un'istanza di entità e la memorizza internamente. Qualsiasi query successiva a che richiede un'entità con la stessa chiave restituisce questa istanza memorizzata . Se i valori nell'archivio dati modificati si continua a ricevere l'entità con valori dal query iniziale

Una risposta attenta:

https://stackoverflow.com/a/3653392/1863179

+8

Versione breve: "Mai usare mai il contesto globale" – Colin

+1

Ho eseguito il debugging come un matto, andando in SSMS e controllando tutto quello che posso trovare perché alcune chiamate non sono state aggiornate ... ora lo so! Grazie! – RemarkLima

4

sottostante Codice aiutato il mio scopo di essere aggiornati con i valori del database freschi . Le forze Voce di comando (oggetto) .Reload() l'oggetto di database per richiamare valori

GM_MEMBERS member = DatabaseObjectContext.GM_MEMBERS.FirstOrDefault(p => p.Username == username && p.ApplicationName == this.ApplicationName); 
DatabaseObjectContext.Entry(member).Reload(); 
4

vi consiglio di usare un po 'a tutti MergeOption EntitieSet dopo creare il contesto, in questo modo:

var objSetProps = ctx.GetType().GetProperties().Where(prop => prop.PropertyType.IsGenericType && prop.PropertyType.GetGenericTypeDefinition() == typeof(ObjectSet<>)); 
foreach (PropertyInfo objSetProp in objSetProps) 
{ 
    ObjectQuery objSet = (ObjectQuery)objSetProp.GetValue(ctx, BindingFlags.GetProperty, null, null, null); 
    objSet.MergeOption = MergeOption.PreserveChanges; 
} 

Leggi a proposito di MergeOption: http://msdn.microsoft.com/en-us/library/system.data.objects.mergeoption.aspx Il tuo testamento utilizzerà NoTracking, credo.

Ma, vuoi liberare le entità "memorizzate nella cache", staccandola.

var entidades = Ctx.ObjectStateManager.GetObjectStateEntries(EntityState.Added | EntityState.Deleted | EntityState.Modified | EntityState.Unchanged); 
foreach (var objectStateEntry in entidades) 
    Ctx.Detach(objectStateEntry.Entity); 

Dove Ctx è il mio Contesto.

2

In primo luogo non suggerirei di modificare il database esterno al sistema a meno che non si stia eseguendo solo test e sviluppo.

EF DbContext contiene un'interfaccia IDisposable. Per rilasciare qualsiasi dato memorizzato nella cache, effettuare le chiamate Dispose manualmente o posizionare l'oggetto del database all'interno di un blocco.

 using (SchoolBriefcaseEntities datamodel = new SchoolBriefcaseEntities()) 
     { 
      List<Compliance> compliance = new List<Compliance>(); 
      IList<ComplianceModel> complianceModel; 
      if (HttpContext.Current.User.IsInRole("SuperAdmin")) 
      { 
       compliance = datamodel.Compliances.Where(c => c.School.DistrictId == districtId).ToList(); 
      } 
     } 

Ciò assicurerà che il contesto venga cancellato e ricreato la prossima volta che viene utilizzato. Assicurati di farlo per tutte le tue chiamate e non solo per quelle con cui hai problemi.

2

Sospetto che il problema sottostante qui sia che il tuo DbContext è in giro troppo a lungo. Posso dire dal fatto che si sta utilizzando HttpContext che si dispone di un'applicazione web, e General guidelines when working with DbContext includere

Quando si lavora con le applicazioni Web, utilizzare un'istanza contesto per richiesta.

Se si utilizza MVC è possibile utilizzare il pattern Dispose nel controller come questo:

public class EmployeeController : Controller 
{ 
    private EmployeeContext _context; 

    public EmployeeController() 
    { 
     _context = new EmployeeContext(); 
    } 

    public ActionResult Index() 
    { 
     return View(_context.Employees.ToList()); 
    } 

    protected override void Dispose(bool disposing) 
    { 
     if (disposing) 
     { 
      _context.Dispose(); 
     } 
     base.Dispose(disposing); 
    } 
} 

Ma si dovrebbe davvero essere alla ricerca di iniezione di dipendenza per manage the DbContext lifetime

0

paio di cose che puoi fare.

  1. Utilizzare un nuovo contesto. Le entità memorizzate nella cache sono memorizzate nel contesto. L'utilizzo di un nuovo contesto gli impedisce di utilizzare la cache.
  2. Se si desidera realmente un contesto globale/di lunga durata, si hanno due opzioni secondarie: a.) Chiamare sempre il metodo Ricarica. db.Entry (entity) .Reload() ... questo costringe il contesto a ricaricare quell'entità. b.) Utilizzare un oggetto SqlDependency per rilevare quando i record cambiano e ricaricare le entità secondo necessità. https://code.msdn.microsoft.com/How-to-use-SqlDependency-5c0da0b3
2

Penso che quello che ti serve è GetDatabaseValues(). E 'usato come:

context.Entry(/*your entry*/).GetDatabaseValues(); 

Informazioni qui di seguito è da msdn:

I valori attuali sono i valori che le proprietà dell'entità attualmente contengono. I valori originali sono i valori letti dal database quando l'entità è stata interrogata. I valori del database sono i valori così come sono attualmente memorizzati nel database.Ottenere i valori del database è utile quando i valori nel database possono avere modificato poiché l'entità è stata interrogata, ad esempio quando una modifica simultanea a del database è stata effettuata da un altro utente.

7

Penso che dovresti seguire alcune delle altre soluzioni qui, ma sembra che tu voglia cancellare la cache. È possibile ottenere ciò facendo quanto segue:

var count = datamodel.Compliances.Local.Count; // number of items in cache (ex. 30) 

datamodel.Compliances.Local.ToList().ForEach(c => { 
    datamodel.Entry(c).State = EntityState.Detached; 
}); 

count = datamodel.Compliances.Local.Count; // 0 
+0

Questa è stata la soluzione migliore per il problema. Basta cancellare la cache del DbContext e sei a posto. –