Operaciones masivas en BD
Por defecto, Crono (que usa Entity Framework) rastrea los cambios de las entidades y los envía a la base de datos al llamar a SaveChanges, en lotes y solo para lo que realmente cambió. Es un mecanismo eficiente y cómodo para inserciones, actualizaciones y borrados de propósito general.
Sin embargo, a veces conviene ejecutar comandos de actualización o borrado directamente en la base de datos, sin involucrar al rastreador de cambios. EF Core lo permite con ExecuteUpdate y ExecuteDelete, que se aplican a una consulta LINQ y actualizan o eliminan entidades sin cargarlas en memoria. Muchas entidades pueden modificarse con un solo comando, lo que resulta en operaciones mucho más eficientes.
Ejemplos
// Borrado masivo de todas las propiedades localizadas
// de un grupo de entidades eliminadas.
await _db.PropiedadesLocalizadas
.Where(x => idsEliminados.Contains(x.EntidadId) && x.ClaveGrupoLocal == "MiEntidad")
.ExecuteDeleteAsync(cancelToken);
// Actualización masiva: añadir " (antiguo)" al nombre
// de los registros creados antes de 2020.
await _db.Prestamos
.Where(x => x.FechaCreacionUtc.Year < 2020)
.ExecuteUpdateAsync(x => x.SetProperty(p => p.Nombre, p => p.Nombre + " (antiguo)"), cancelToken);
Consideraciones importantes
ExecuteUpdate y ExecuteDelete complementan, no reemplazan, al mecanismo de SaveChanges. Ten en cuenta que:
- Se omite el sistema de interceptores (ver Interceptores): no se ejecutan validaciones, auditoría ni invalidación de caché asociadas al guardado.
- Los cambios concretos deben especificarse explícitamente; EF no los detecta automáticamente.
- Las entidades ya rastreadas no se mantienen sincronizadas con los cambios enviados.
- Puede que necesites enviar comandos en el orden correcto para no violar restricciones (por ejemplo, borrar los dependientes antes que el principal).
Como se omiten los interceptores, evita ExecuteDelete/ExecuteUpdate sobre entidades cuyo guardado dependa de lógica de interceptores (auditoría, eliminación lógica, invalidación de caché, etc.), salvo que manejes esos efectos manualmente.
Para insertar filas de bajo nivel también existe InsertarEn en el ProveedorDatos, que ejecuta un INSERT INTO y devuelve el identificador de la fila insertada (ver Acceso a datos).