2012-10-04 11 views
43

Inizialmente ho creduto cheImpostazioni globali per AsNoTracking()?

context.Configuration.AutoDetectChangesEnabled = false; 

sarebbe disattivare il rilevamento delle modifiche. Ma no. Attualmente ho bisogno di usare AsNoTracking() su tutte le mie query LINQ (per il mio livello di sola lettura). Esiste un'impostazione globale per disabilitare il monitoraggio su DbContext?

risposta

14

Poiché questa domanda non è contrassegnata con una specifica versione EF, volevo menzionare che in EF Core il comportamento può essere configured at the context level.

È inoltre possibile modificare il comportamento di monitoraggio di default a livello di contesto esempio:

using (var context = new BloggingContext()) 
{ 
    context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking; 

    var blogs = context.Blogs.ToList(); 
} 
+0

il tuo link mostrami l'errore –

+0

@AliYousefie grazie, l'ho risolto. –

33

Che dire di metodo semplicemente esponendo come questo sul vostro contesto derivato e usarlo per le query:

public IQueryable<T> GetQuery<T>() where T : class { 
    return this.Set<T>().AsNoTracking(); 
} 

impostazione AsNoTracking non è a livello globale possibile. È necessario impostarlo per ogni query o per ogni ObjectSet (non DbSet). L'ultimo approccio richiede l'utilizzo dell'API ObjectContext.

var objectContext = ((IObjectContextAdapter)dbContext).ObjectContext; 
var set = objectContext.CreateObjectSet<T>(); 
set.MergeOption = MergeOption.NoTracking; 
// And use set for queries 
+1

Come farebbe un unirsi tra Entit quando esporre solo una singola entità come GetQuery ? Grazie per la risposta però. – Vindberg

+0

è possibile unire i risultati di due diverse chiamate 'GetQuery' –

+0

E 'possibile, ma poi ho bisogno di ripetere la configurazione del mio repository generico:/Ma grazie per il suggerimento. – Vindberg

2

Si potrebbe fare qualcosa di simile nel tuo DbContext:

public void ObjectContext_OnObjectMaterialized(Object objSender, ObjectMaterializedEventArgs e) 
{ 
    Entry(e.Entity).State = EntityState.Detached; 
} 

Ogni volta che un oggetto è materializzato dal contesto, verrà staccato e non più rintracciato.

+0

Penso che funzioni ma forse non è il modo migliore per farlo. AsNoTracking() per quanto ne so non collega e scollega oggetti. –

+0

La risposta qui elabora la differenza tra i due. http://stackoverflow.com/a/20163424/219072 Suona come AsNoTracking() è sicuramente l'approccio preferito. – emragins

2

Aggiornamento: questo non ha funzionato. Vedi i commenti!

Odio quando cerco StackOverflow e la risposta è: "Non puoi!" oppure "Potresti, ma solo se cambi completamente ogni singola chiamata che hai mai fatto."

Riflettere qualcuno? Speravo che questa sarebbe stata un'impostazione di DbContext. Ma poiché non lo è, ne ho fatto uno usando la riflessione.

Questo pratico piccolo metodo imposterà AsNoTracking su tutte le proprietà di tipo DbSet.

private void GloballySetAsNoTracking() 
    { 
     var dbSetProperties = GetType().GetProperties(); 
     foreach (PropertyInfo pi in dbSetProperties) 
     { 
      var obj = pi.GetValue(this, null); 
      if (obj.GetType().IsGenericType && obj.GetType().GetGenericTypeDefinition() == typeof(DbSet<>)) 
      { 
       var mi = obj.GetType().GetMethod("AsNoTracking"); 
       mi.Invoke(obj, null); 
      } 
     } 
    } 

Aggiungerlo a un costruttore DbContext sovraccarico.

public ActivationDbContext(bool proxyCreationEnabled, bool lazyLoadingEnabled = true, bool asNoTracking = true) 
    { 
     Configuration.ProxyCreationEnabled = proxyCreationEnabled; 
     Configuration.LazyLoadingEnabled = lazyLoadingEnabled; 
     if (asNoTracking) 
      GloballySetAsNoTracking(); 
    } 

Usa la riflessione, il che significa che qualcuno commenterà rapidamente che si tratta di un successo in termini di prestazioni. Ma è davvero tanto un successo? Dipende dal tuo caso d'uso.

+3

Non ho provato questo, ma per quanto ne so, 'AsNoTracking()' restituisce solo il set corrente come 'IQueryable non tracciato '. Chiamarlo su 'DbSet' non rende le successive query non tracciate. Quello che ho capito da questo codice è che stai chiamando 'AsNoTracking()' su tutti i tuoi set, ma ciò non fa nulla a meno che tu non stia usando il queryable restituito per qualsiasi cosa – Jcl

+0

@Jcl, dovrò verificarlo. Sembra funzionare per me. – Rhyous

+1

Al momento non ho tempo per testarlo, ma a prima vista mi sembra dubbioso. Se funziona, vorrebbe dire che ogni volta che si chiama 'AsNoTracking()' su un 'DbSet' in un contesto, tutte le query successive su quel' DbSet' nello stesso contesto sarebbero non tracciate ... e che sarebbe essere un comportamento strano (specialmente considerando che non c'è alcun 'AsTracking()' da compensare). Se questo funziona davvero, direi che è un bug ... o una funzionalità non documentata :-) – Jcl

0

Nel mio caso, poiché avevo bisogno di tutto il contesto ad essere di sola lettura, piuttosto che di lettura/scrittura.

Quindi ho apportato una modifica al file tt e modificato tutte le proprietà di DbContext per restituire DbQuery anziché DbSet, rimosso i set da tutte le proprietà e per ottenere, ho restituito il modello.AsNoTracking()

Ad esempio:

public virtual DbQuery<Campaign> Campaigns { get{ return Set<Campaign>().AsNoTracking();} }

Il modo in cui ho fatto questo nel modello TT è:

public string DbQuery(EntitySet entitySet) 
 
    { 
 
     return string.Format(
 
      CultureInfo.InvariantCulture, 
 
      "{0} virtual DbQuery<{1}> {2} {{ get{{ return Set<{1}>().AsNoTracking();}} }}", 
 
      Accessibility.ForReadOnlyProperty(entitySet), 
 
      _typeMapper.GetTypeName(entitySet.ElementType), 
 
      _code.Escape(entitySet)); 
 
    }