Impostazioni globali per AsNoTracking ()?

All’inizio ci credevo

context.Configuration.AutoDetectChangesEnabled = false; 

disabiliterebbe 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?

Poiché questa domanda non è contrassegnata da una specifica versione EF, volevo menzionare che in EF Core il comportamento può essere configurato a livello di contesto .

Puoi anche modificare il comportamento di tracciamento predefinito al livello di istanza del contesto:

 using (var context = new BloggingContext()) { context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking; var blogs = context.Blogs.ToList(); } 

Che dire semplicemente esponendo un metodo come questo sul tuo contesto derivato e usalo per le query:

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

L’impostazione di AsNoTracking livello globale non è ansible. È 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(); set.MergeOption = MergeOption.NoTracking; // And use set for queries 

Potresti 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 object viene materializzato dal tuo contesto, verrà staccato e non più tracciato.

Aggiornamento: questo non ha funzionato davvero. Vedi i commenti!

Lo 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); } } } 

Aggiungilo 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 nelle prestazioni. Ma è davvero tanto un successo? Dipende dal tuo caso d’uso.

Nel mio caso, poiché avevo bisogno che l’intero contesto fosse di sola lettura anziché di lettura / scrittura.

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

Per esempio:

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