El Tracking es el mecanismo por el cual Entity Framework realiza un seguimiento de los cambios en las entidades que se recuperan de la base de datos.
El Tracking es una de las mejores características de Entity Framework. Pero también puede ser una de las más costosas en cuanto a rendimiento.
Por ese motivo, en ocasiones nos va a convenir desactivar el sistema usando NoTrakcing
, para optimizar nuestras aplicaciones.
Esto es especialmente importante cuando trabajamos con grandes volúmenes de datos o consultas que no requieren modificaciones en las entidades.
¿Qué es el Tracking en Entity Framework?
El Tracking es el sistema que permite que, cuando realizamos modificaciones en estas entidades Entity Framework pueda determinar los cambios.
Con esto, puede generar las sentencias SQL necesarias para actualizar la base de datos cuando llamamos a SaveChanges()
.
// Consulta con Tracking (por defecto)
var producto = context.Productos.FirstOrDefault(p => p.Id == 1);
// Modificamos la entidad
producto.Precio = 99.99m;
// Guardamos los cambios en la base de datos
context.SaveChanges();
En este ejemplo,
- Entity Framework realiza un seguimiento de la entidad
producto
. - Cuando modificamos el precio y llamamos a
SaveChanges()
, - EF detecta el cambio y genera una sentencia SQL
UPDATE
para actualizar el registro en la base de datos.
Pero, lógicamente, este seguimiento de los cambios viene con un trabajo detrás, que no siempre vamos a necesitar. Por eso podemos desactivarlo si no lo necesitamos.
¿Qué es el No-Tracking en Entity Framework?
El No-Tracking es una técnica que desactiva el seguimiento de las entidades recuperadas. Esto significa que Entity Framework no realizará un seguimiento de los cambios en estas entidades.
Para desactivar el seguimiento, utilizamos el método AsNoTracking()
.
using (var context = new ApplicationDbContext())
{
// Consulta con No-Tracking
var productos = context.Productos
.AsNoTracking()
.ToList();
// Los cambios en estas entidades no serán rastreados
foreach (var producto in productos)
{
producto.Precio = 99.99m; // Este cambio no se reflejará en la base de datos
}
}
En este caso,
- Las entidades recuperadas no están siendo rastreadas por Entity Framework.
- Cualquier modificación que hagamos en estas entidades no se reflejará en la base de datos al llamar a
SaveChanges()
.
AsNoTracking
con proyecciones
En ocasiones, no necesitamos recuperar entidades completas, sino solo ciertos campos. En estos casos, igualmente podemos AsNoTracking
con proyecciones para mejorar aún más el rendimiento.
using (var context = new ApplicationDbContext())
{
var productos = context.Productos
.AsNoTracking()
.Select(p => new { p.Nombre, p.Precio })
.ToList();
}
En este ejemplo, solo recuperamos los campos Nombre
y Precio
de los productos, lo que reduce la cantidad de datos transferidos y mejora el rendimiento.
Actualizar una entidad cargada con AsNoTracking
Aunque hayamos cargado una entidad con AsNoTracking
, aún podemos actualizarla. Pero tendremos que gestionar el estado manualmente (no tenemos tracking).
Para ello tendremos que adjuntarla manualmente, y cambiar el estado a Modified.
var entidadSinTracking = context.Entidades
.AsNoTracking()
.FirstOrDefault(e => e.Id == id);
// Realizas los cambios en la entidad
entidadSinTracking.Nombre = "Nuevo Nombre";
// Adjuntas la entidad al contexto (sin hacer seguimiento todavía)
context.Attach(entidad);
// Adjuntas y marcas como modificada
context.Entry(entidadSinTracking).State = EntityState.Modified;
// Guardas los cambios
context.SaveChanges();
- Debes asegurarte de que los campos clave estén correctamente asignados, ya que EF usará eso para saber qué registro debe actualizar (como el Id)
- EF no puede detectar qué propiedades cambiaron cuando usas State = Modified, así que actualizará todas las columnas de esa fila, no solo las modificadas.
- Si tu entidad tiene propiedades de navegación, ten cuidado con relaciones que no quieres tocar; podrían actualizarse o intentar insertarse si no están bien controladas.
Hay más formas de cambiar el estado de una entidad No-Tracking. Por ejemplo, el comando Update
es básicamente equivalente a Atatch
y cambiar el estado.
context.Update(producto)
Por otro lado, si queremos marcar únicamente el estado de una propiedad, podríamos hacerlo así
context.Entry(producto).Property(p => p.Precio).IsModified = true;
Cuando usar No-Tracking
Las entidades cargas con No-Tracking reducen la sobrecarga de memoria y mejorar la velocidad en el acceso de la base de datos (la mejoran mucho!)
Pero claro, perdemos el tracking 🙄. Así que si hacemos cambios en las entidades, no vamos a poder guardarlas (fácilmente) con SaveChanges
.
Por tanto, es útil en
- Consultas de solo lectura: Si solo necesitas recuperar datos para mostrarlos o procesarlos sin modificarlos
- Grandes volúmenes de datos: Cuando trabajas con grandes conjuntos de datos que requieren una gran optimización del rendimiento