tutorial homepage functions framework first enum code entity-framework change-tracking

entity-framework - homepage - function in entity framework



ConfiguraciĆ³n global para AsNoTracking()? (5)

¿Qué tal si simplemente exponemos un método como este en su contexto derivado y lo usamos para consultas?

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

Establecer AsNoTracking globalmente no es posible. Debe establecerlo para cada consulta o por cada ObjectSet (no DbSet ). El último enfoque requiere el uso de ObjectContext API.

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

Originalmente creía que

context.Configuration.AutoDetectChangesEnabled = false;

Deshabilitaría el seguimiento de cambios. Pero no. Actualmente necesito usar AsNoTracking() en todas mis consultas LINQ (para mi capa de solo lectura). ¿Hay una configuración global para deshabilitar el seguimiento en DbContext?


Actualización: Esto realmente no funcionó. ¡Ver comentarios!

Odio cuando busco en y la respuesta es: "¡No puedes!" o "Podrías, pero solo si cambias por completo cada llamada que hayas hecho".

Reflexión a alguien? Esperaba que fuera una configuración de DbContext. Pero como no lo es, hice uno usando la reflexión.

Este práctico pequeño método establecerá AsNoTracking en todas las propiedades del 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); } } }

Añádalo a un constructor de DbContext sobrecargado.

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

Utiliza reflexión, lo que significa que alguien comentará rápidamente que se trata de un golpe de rendimiento. Pero, ¿realmente es un gran éxito? Depende de tu caso de uso.


Como esta pregunta no está etiquetada con una versión específica de EF, quería mencionar que en EF Core el comportamiento se puede configurar en el contexto .

También puede cambiar el comportamiento de seguimiento predeterminado en el nivel de instancia de contexto:

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


En mi caso, ya que necesitaba todo el contexto para ser de solo lectura en lugar de leer / escribir.

Así que hice un cambio en el archivo tt, y cambié todas las propiedades de DbContext para devolver DbQuery en lugar de DbSet, eliminé los conjuntos de todas las propiedades y, para los get, devolví el Model.AsNoTracking ()

Por ejemplo:

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

La forma en que hice esto en la plantilla tt es:

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


Podrías hacer algo como esto en tu DbContext:

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

Cada vez que un objeto se materializa según su contexto, se desconectará y ya no se rastreará.