2012-10-04 11 views
43

principio yo creía queConfiguración global para AsNoTracking()?

context.Configuration.AutoDetectChangesEnabled = false; 

hará imposible 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?

Respuesta

14

Dado que esta pregunta no está etiquetada con una versión EF específica, quería mencionar que en EF Core el comportamiento puede ser configured at the context level.

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

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

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

su enlace muéstrame el error –

+0

@AliYousefie gracias, lo he solucionado. –

33

¿Qué pasa con la simple exposición método como este en su contexto derivados y utilizarla para consultas:

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

Configuración AsNoTracking a nivel mundial no es posible. Debe configurarlo 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 
+1

Cómo haría una unirse entre Entit s cuando solo se expone una sola entidad como GetQuery ? Gracias por la respuesta. – Vindberg

+0

puede unir los resultados de dos llamadas diferentes a 'GetQuery' –

+0

Es posible, pero luego tengo que volver a hacer la configuración genérica de mi repositorio:/Pero gracias por la sugerencia. – Vindberg

2

Se podría hacer algo como esto en su DbContext:

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

Cada vez que un objeto se materializa por su contexto, será separada y ya no siguió.

+0

Creo que esto funciona, pero tal vez no sea la mejor manera de hacerlo. AsNoTracking() por lo que sé, no adjuntar y separar objetos. –

+0

La respuesta aquí explica la diferencia entre los dos. http://stackoverflow.com/a/20163424/219072 Parece que AsNoTracking() es definitivamente el enfoque preferido. – emragins

2

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

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

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

Este pequeño y útil método configurará 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); 
      } 
     } 
    } 

Agréguela 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 la 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.

+3

No he probado esto, pero hasta donde yo sé, 'AsNoTracking()' solo devuelve el conjunto actual como un 'IQueryable' no rastreado. Llamarlo al 'DbSet' no hace que las siguientes consultas no sean rastreadas. Lo que entiendo de este código es que está llamando 'AsNoTracking()' en todos sus conjuntos, pero eso no sirve de nada a menos que esté usando las consultas devueltas para cualquier cosa – Jcl

+0

@Jcl, tendré que verificar eso. Parece estar trabajando para mí. – Rhyous

+1

No tengo tiempo ahora mismo para probarlo, pero a primera vista me parece dudoso. Si esto funciona, significaría que cada vez que llame a 'AsNoTracking()' en un 'DbSet' en un contexto, todas las consultas subsiguientes en ese' DbSet' en el mismo contexto no se rastrearán ... y eso ser un comportamiento extraño (especialmente considerando que no hay 'AsTracking()' para compensar). Si esto realmente funciona, diría que es un error ... o una característica no documentada :-) – Jcl

0

En mi caso ya que necesitaba todo el contexto a ser de sólo lectura en lugar de lectura/escritura.

Así que hice un cambio en el archivo tt, y cambié todas las propiedades DbContext para devolver DbQuery en lugar de DbSet, eliminé los conjuntos de todas las propiedades y, para los get, devolví el Modelo.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)); 
 
    }

Cuestiones relacionadas