tutorial mvc framework first example español code c# entity-framework entity-framework-4.1 dbcontext dbset

c# - mvc - ¿Puede obtener el DbContext de un DbSet?



entity framework database first (4)

¿Por qué haces esto en el DbSet? Intenta hacerlo en el DbContext en su lugar:

public static void AddRangeFast<T>(this DbContext context, IEnumerable<T> items) where T : class { var detectChanges = context.Configuration.AutoDetectChangesEnabled; try { context.Configuration.AutoDetectChangesEnabled = false; var set = context.Set<T>(); foreach (var item in items) { set.Add(item); } } finally { context.Configuration.AutoDetectChangesEnabled = detectChanges; } }

Entonces usarlo es tan simple como:

using (var db = new MyContext()) { // slow add db.MyObjects.Add(new MyObject { MyProperty = "My Value 1" }); // fast add db.AddRangeFast(new[] { new MyObject { MyProperty = "My Value 2" }, new MyObject { MyProperty = "My Value 3" }, }); db.SaveChanges(); }

En mi aplicación, a veces es necesario guardar 10.000 o más filas en la base de datos en una sola operación. Descubrí que simplemente iterar y agregar cada elemento uno a la vez puede llevar más de media hora.

Sin embargo, si deshabilito AutoDetectChangesEnabled, toma ~ 5 segundos (que es exactamente lo que quiero)

Estoy tratando de hacer un método de extensión llamado "AddRange" a DbSet que deshabilitará AutoDetectChangesEnabled y luego lo volverá a habilitar al finalizar.

public static void AddRange<TEntity>(this DbSet<TEntity> set, DbContext con, IEnumerable<TEntity> items) where TEntity : class { // Disable auto detect changes for speed var detectChanges = con.Configuration.AutoDetectChangesEnabled; try { con.Configuration.AutoDetectChangesEnabled = false; foreach (var item in items) { set.Add(item); } } finally { con.Configuration.AutoDetectChangesEnabled = detectChanges; } }

Entonces, mi pregunta es: ¿hay una manera de obtener el DbContext desde un DbSet? No me gusta hacer que sea un parámetro, parece que debería ser innecesario.



Sí, puede obtener el DbContext desde un DbSet<TEntity> , pero la solución es muy pesada. He proporcionado un ejemplo de cómo hacer esto a continuación.

DbContext el siguiente código y pude recuperar exitosamente la instancia DbContext desde la cual se generó el DbSet . Tenga en cuenta que, aunque sí responde a su pregunta, es casi seguro que hay una solución mejor para su problema .

public static class HackyDbSetGetContextTrick { public static DbContext GetContext<TEntity>(this DbSet<TEntity> dbSet) where TEntity: class { object internalSet = dbSet .GetType() .GetField("_internalSet",BindingFlags.NonPublic|BindingFlags.Instance) .GetValue(dbSet); object internalContext = internalSet .GetType() .BaseType .GetField("_internalContext",BindingFlags.NonPublic|BindingFlags.Instance) .GetValue(internalSet); return (DbContext)internalContext .GetType() .GetProperty("Owner",BindingFlags.Instance|BindingFlags.Public) .GetValue(internalContext,null); } }

Ejemplo de uso:

using(var originalContextReference = new MyContext()) { DbSet<MyObject> set = originalContextReference.Set<MyObject>(); DbContext retrievedContextReference = set.GetContext(); Debug.Assert(ReferenceEquals(retrievedContextReference,originalContextReference)); }

Explicación:

Según Reflector, DbSet<TEntity> tiene un campo privado _internalSet de tipo InternalSet<TEntity> . El tipo es interno a la dll EntityFramework. Hereda de InternalQuery<TElement> (donde TEntity : TElement ). InternalQuery<TElement> también es interno a la dll EntityFramework. Tiene un campo privado _internalContext de tipo InternalContext . InternalContext también es interno de EntityFramework. Sin embargo, InternalContext expone una propiedad pública de DbContext llamada Owner . Por lo tanto, si tiene una DbSet<TEntity> , puede obtener una referencia al propietario de DbContext , accediendo a cada una de esas propiedades de manera reflexiva y DbContext resultado final a DbContext .

Actualización de @LoneyPixel

En EF7 hay un campo privado _context directamente en la clase que implementa DbSet. No es difícil exponer este campo públicamente.


tal vez podría crear un ayudante que deshabilitó esto para usted y luego simplemente llamar al ayudante desde el método AddRange