Estoy ejecutando un código de corrección que se ejecuta sobre una gran pila de entidades, a medida que avanza, su velocidad disminuye, eso se debe a que la cantidad de entidades rastreadas en el contexto aumenta con cada iteración, puede llevar mucho tiempo, así que estoy guardando los cambios al final de cada iteración. Cada iteración es independiente y no cambia las entidades cargadas previamente.
Sé que puedo desactivar el seguimiento de cambios, pero no quiero, porque no es un código de inserción masiva, sino cargando las entidades y calculando algunas cosas y si los números no son correctos, configure los nuevos números y actualice / elimine / cree algunas entidades adicionales. Sé que puedo crear un nuevo DbContext para cada iteración y probablemente eso funcionaría más rápido que hacerlo todo en la misma instancia, pero estoy pensando que podría haber una mejor manera.
Entonces la pregunta es; ¿Hay alguna forma de borrar las entidades cargadas previamente en el contexto de la base de datos?
fuente
context.Entry(entity).State = EntityState.Detached
y dejará de rastrear esa entidad en particular.Respuestas:
Puede agregar un método a su
DbContext
o un método de extensión que use ChangeTracker para separar todas las entidades agregadas, modificadas y eliminadas:public void DetachAllEntities() { var changedEntriesCopy = this.ChangeTracker.Entries() .Where(e => e.State == EntityState.Added || e.State == EntityState.Modified || e.State == EntityState.Deleted) .ToList(); foreach (var entry in changedEntriesCopy) entry.State = EntityState.Detached; }
fuente
var entity
debería ser realmente,var entry
ya que es la entrada, no la Entidad real)1. Posibilidad: separar la entrada
Cuando separa la entrada, el rastreador de cambios dejará de rastrearla (y debería dar como resultado un mejor rendimiento)
Ver: http://msdn.microsoft.com/de-de/library/system.data.entitystate(v=vs.110).aspx
2. Posibilidad: trabajar con su propio
Status
campo + contextos desconectadosTal vez desee controlar el estado de su entidad de forma independiente para poder usar gráficos desconectados. Agregue una propiedad para el estado de la entidad y transforme este estado en
dbContext.Entry(entity).State
cuando realice operaciones (use un repositorio para hacer esto)public class Foo { public EntityStatus EntityStatus { get; set; } } public enum EntityStatus { Unmodified, Modified, Added }
Consulte el siguiente enlace para ver un ejemplo: https://www.safaribooksonline.com/library/view/programming-entity-framework/9781449331825/ch04s06.html
fuente
Estoy ejecutando un servicio de Windows que actualiza los valores cada minuto y he tenido el mismo problema. Intenté ejecutar la solución @DavidSherrets, pero después de unas horas esto también se volvió lento. Mi solución fue simplemente crear un nuevo contexto como este para cada nueva ejecución. Simple pero funciona.
_dbContext = new DbContext();
fuente
Me encontré con este problema y, finalmente, encontré una mejor solución para aquellos que usan la típica inyección de dependencia de .NET Core. Puede usar un DbContext con ámbito para cada operación. Eso se restablecerá
DbContext.ChangeTracker
para queSaveChangesAsync()
no se atasque al verificar las entidades de iteraciones pasadas. Aquí hay un ejemplo de método de controlador ASP.NET Core:/// <summary> /// An endpoint that processes a batch of records. /// </summary> /// <param name="provider">The service provider to create scoped DbContexts. /// This is injected by DI per the FromServices attribute.</param> /// <param name="records">The batch of records.</param> public async Task<IActionResult> PostRecords( [FromServices] IServiceProvider provider, Record[] records) { // The service scope factory is used to create a scope per iteration var serviceScopeFactory = provider.GetRequiredService<IServiceScopeFactory>(); foreach (var record in records) { // At the end of the using block, scope.Dispose() will be called, // release the DbContext so it can be disposed/reset using (var scope = serviceScopeFactory.CreateScope()) { var context = scope.ServiceProvider.GetService<MainDbContext>(); // Query and modify database records as needed await context.SaveChangesAsync(); } } return Ok(); }
Dado que los proyectos ASP.NET Core generalmente usan DbContextPool, esto ni siquiera crea / destruye los objetos DbContext. (En caso de que estuviera interesado, DbContextPool realmente llama a
DbContext.ResetState()
yDbContext.Resurrect()
, pero no recomendaría llamarlos directamente desde su código, ya que probablemente cambiarán en futuras versiones). Https://github.com/aspnet/EntityFrameworkCore/blob/v2 .2.1 / src / EFCore / Internal / DbContextPool.cs # L157fuente
Desde EF Core 3.0 hay una API interna que puede restablecer el ChangeTracker. No use esto en el código de producción, lo menciono ya que puede ayudar a alguien en las pruebas según el escenario.
using Microsoft.EntityFrameworkCore.Internal; _context.GetDependencies().StateManager.ResetState();
Como dice el comentario sobre el código;
fuente
Bueno, mi opinión es que, en mi experiencia, EF, o siendo cualquier forma, no funciona bien bajo demasiada presión o modelo complejo.
Si no quiere rastrear, realmente diría ¿por qué incluso hacer orm?
Si la velocidad es la fuerza principal, nada supera a los procedimientos almacenados y la buena indexación.
Y más allá, si sus consultas son siempre por id, considere usar un nosql o quizás sql con solo key y json. Esto evitaría el problema de impedancia entre clases y tablas.
Para el escenario de su caso, cargar cosas en objetos de esa manera me parece muy lento. Realmente en su caso, los procedimientos almacenados son mejores porque evita el transporte de datos a través de la red, y sql es mucho más rápido y está optimizado para administrar la agregación y cosas así.
fuente