BulkMerge (Upsert) en EF Core con Entity Framework Extensions te permite insertar o actualizar (Upsert) miles de registros en una sola operación masiva, decidiendo automáticamente si cada elemento se inserta (si no existe) o se actualiza (si ya existe).
🧬 Ejemplo práctico: mantén tu catálogo al día con un solo paso
Caso real: recibes un catálogo de productos desde una API o archivo JSON. Algunos productos ya existen en la base (deben actualizarse) y otros son nuevos (deben insertarse). Con EF Core BulkMerge (Upsert) resuelves ambos pasos en una sola línea, sin bucles ni validaciones manuales.
// @nuget: Z.EntityFramework.Extensions.EFCore
using Z.EntityFramework.Extensions;
using (var context = new AppDbContext())
{
var productos = new List<Producto>
{
new Producto { Nombre = "Teclado mecánico", Precio = 59.90m },
new Producto { Nombre = "Mouse inalámbrico", Precio = 29.90m },
new Producto { Nombre = "Monitor 24 pulgadas", Precio = 149.00m }
};
// Inserta si no existe, actualiza si ya existe (Upsert)
context.BulkMerge(productos);
// Versión asíncrona para apps Web/API
await context.BulkMergeAsync(productos);
}
💻 Ejemplo interactivo en .NET Fiddle
Haz clic en el siguiente enlace para abrir el ejemplo de BulkMerge (Upsert) en EF Core con Entity Framework Extensions directamente en tu navegador:
🔗 Ver directamente en .NET Fiddle
También puedes probarlo aquí mismo, editar el código, ejecutarlo y observar el resultado en tiempo real:
🔁 Uso síncrono y asíncrono
BulkMerge (Upsert) en EF Core con Entity Framework Extensions ofrece variantes sync y async.
En aplicaciones Web/API se recomienda async para no bloquear hilos.
// @nuget: Z.EntityFramework.Extensions.EFCore
using Z.EntityFramework.Extensions;
using (var context = new AppDbContext())
{
var productos = ObtenerProductosDesdeJson(); // tu fuente externa
// 👉 Síncrono (desktop, jobs simples)
context.BulkMerge(productos);
// 👉 Asíncrono (Web/API)
await context.BulkMergeAsync(productos);
}
Con opciones (clave personalizada, ignorar campos, relaciones):
// @nuget: Z.EntityFramework.Extensions.EFCore
using Z.EntityFramework.Extensions;
// Sync
context.BulkMerge(productos, options =>
{
options.ColumnPrimaryKeyExpression = x => new { x.Codigo };
options.IgnoreOnMergeInsertExpression = x => new { x.FechaCreacion };
options.IgnoreOnMergeUpdateExpression = x => new { x.UsuarioModificacion };
options.IncludeGraph = true;
});
// Async
await context.BulkMergeAsync(productos, options =>
{
options.ColumnPrimaryKeyExpression = x => new { x.Codigo };
options.IgnoreOnMergeInsertExpression = x => new { x.FechaCreacion };
options.IgnoreOnMergeUpdateExpression = x => new { x.UsuarioModificacion };
options.IncludeGraph = true;
});
🔧 Instalación rápida
Antes de usar BulkMerge (Upsert), instala el paquete oficial de Entity Framework Extensions.
👉 Aquí se instala (descarga oficial)
# .NET CLI
dotnet add package Z.EntityFramework.Extensions.EFCore
# PMC
PM> NuGet\Install-Package Z.EntityFramework.Extensions.EFCore
// using requerido en tu código C#
using Z.EntityFramework.Extensions;
😎 Contexto práctico: el problema de sincronizar datos externos
EF Core BulkMerge (Upsert) de Entity Framework Extensions resuelve el desafío clásico de sincronizar datos externos con tu base de datos en una sola operación masiva.
Cuando trabajas con aplicaciones modernas, es común recibir datos desde fuentes externas:
- Archivos CSV o Excel.
- Respuestas JSON de una API.
- Integraciones con sistemas de terceros.
El problema surge cuando intentas sincronizar esos datos con tu base:
- Si usas
Add()
oUpdate()
debes validar uno por uno. - Esto implica múltiples consultas, bucles y llamadas a la base.
- Con miles de registros, el rendimiento cae drásticamente.
BulkMerge resuelve esto con un solo método:
- Si el registro existe (según clave primaria o personalizada), lo actualiza.
- Si no existe, lo inserta automáticamente.
De esta forma simplificas la lógica de sincronización y reduces la complejidad de tu código.
🚀 ¿Qué es BulkMerge (Upsert) en EF Core con Entity Framework Extensions y por qué usarlo?
BulkMerge en EF Core con Entity Framework Extensions combina inserciones y actualizaciones en un único flujo (Upsert), ideal para mantener la base sincronizada con catálogos y fuentes externas.
Beneficios principales:
- Eficiencia: evita múltiples validaciones manuales.
- Escalabilidad: maneja listas grandes sin sacrificar rendimiento.
- Flexibilidad: admite expresiones personalizadas y entidades relacionadas.
- Claridad: reduce el código repetitivo a una sola línea clara.
🔍 ¿Cómo funciona BulkMerge (Upsert) por dentro?
Para entender por qué BulkMerge es tan eficiente, vale la pena conocer su funcionamiento interno:
- Convierte tu lista externa en una tabla temporal.
- Evalúa la existencia del registro en la base usando la PK o una expresión personalizada.
- Ejecuta un
INSERT
si no existe o unUPDATE
si ya existe. - Devuelve el resultado optimizado en una sola operación SQL.
Este proceso evita que tengas que escribir bucles en C#, logrando sincronizaciones rápidas y seguras incluso con decenas de miles de registros.
⚙️ Opciones avanzadas de BulkMerge (Upsert) en EF Core con Entity Framework Extensions
El método BulkMerge ofrece varias configuraciones que lo hacen aún más flexible:
- ColumnPrimaryKeyExpression → Define una clave personalizada para identificar registros.
- IgnoreOnMergeInsertExpression → Excluye campos específicos durante la inserción.
- IgnoreOnMergeUpdateExpression → Excluye campos durante la actualización.
- IncludeGraph → Inserta o actualiza entidades relacionadas automáticamente, manteniendo relaciones y jerarquías.
context.BulkMerge(productos, options =>
{
options.ColumnPrimaryKeyExpression = x => new { x.Codigo };
options.IgnoreOnMergeInsertExpression = x => new { x.FechaCreacion };
options.IgnoreOnMergeUpdateExpression = x => new { x.UsuarioModificacion };
options.IncludeGraph = true; // Manejo automático de entidades relacionadas
});
❓ Preguntas frecuentes (FAQ)
Resolvemos dudas rápidas sobre BulkMerge (Upsert) en EF Core con Entity Framework Extensions para que apliques el patrón Upsert con confianza.
📌 Comparativa rápida
Operación | Acción | Snippet |
---|---|---|
BulkInsert | Inserta solo nuevos registros | context.BulkInsert(productos); |
BulkUpdate | Actualiza solo existentes | context.BulkUpdate(productos); |
BulkMerge (Upsert) | Inserta o actualiza según exista | context.BulkMerge(productos); |
🧠 ¿Cómo decide BulkMerge si un registro “existe”?
Por defecto, Entity Framework Extensions usa la clave primaria. Puedes personalizarla con ColumnPrimaryKeyExpression
(incluye claves compuestas).
// Clave personalizada (ej. Código)
context.BulkMerge(productos, options => {
options.ColumnPrimaryKeyExpression = x => new { x.Codigo };
});
🧩 ¿Puedo ignorar campos en inserción/actualización?
Sí. Usa IgnoreOnMergeInsertExpression
y IgnoreOnMergeUpdateExpression
para excluir propiedades.
context.BulkMerge(productos, options => {
options.IgnoreOnMergeInsertExpression = x => new { x.FechaCreacion };
options.IgnoreOnMergeUpdateExpression = x => new { x.UsuarioModificacion };
});
🌿 ¿Funciona con entidades relacionadas (hijos)?
Sí. Activa IncludeGraph
para que BulkMerge en EF Core con Entity Framework Extensions preserve relaciones.
context.BulkMerge(pedidos, options => {
options.IncludeGraph = true; // Inserta/actualiza hijos automáticamente
});
📦 ¿Admite listas anónimas o proyecciones?
Sí, puedes usar BulkMerge<T>(anonymousList)
siempre que las propiedades coincidan por nombre y tipo con la entidad.
var anon = new[] { new { Codigo = "A-01", Precio = 59.90m } };
context.BulkMerge<Producto>(anon);
⚡ ¿Hay versiones síncronas y asíncronas?
Sí. Entity Framework Extensions soporta ambas para Web/API y escritorio.
// Sync
context.BulkMerge(productos);
// Async
await context.BulkMergeAsync(productos);
🧩 Compatibilidad y soporte
Resumen de compatibilidad de BulkMerge (Upsert) en EF Core con Entity Framework Extensions y cómo se integra con otros flujos masivos.
Aspecto | Estado | Notas |
---|---|---|
EF Core | ✅ Compatible (versiones modernas) | Verifica tu versión; hoy el artículo se alinea con EF Core 9. |
Proveedor SQL Server | ✅ Recomendado/optimizado | Rendimiento y soporte al día. |
Otros proveedores (PostgreSQL, MySQL, SQLite) | ✅ Soportado | Soportado oficialmente en todos los proveedores listados. |
Operaciones relacionadas | ✅ BulkInsert · BulkUpdate | BulkMerge se complementa bien con estas operaciones. |
Entidades relacionadas | ✅ IncludeGraph | Preserva relaciones y maneja hijos automáticamente. |
⚠️ Errores y soluciones
A continuación verás los errores más comunes al usar EF Core BulkMerge (Upsert) de Entity Framework Extensions, junto con su solución. Haz clic en cada título para desplegar el detalle.
❌ Falta de paquete o using
Problema: el proyecto no compila o no se reconoce BulkMerge
.
Solución: instala el paquete y agrega el using correspondiente.
# .NET CLI
dotnet add package Z.EntityFramework.Extensions.EFCore
# PMC
PM> NuGet\Install-Package Z.EntityFramework.Extensions.EFCore
// using requerido
using Z.EntityFramework.Extensions;
❌ Clave mal definida (PK) o inexistente
Problema: BulkMerge no identifica correctamente si un registro existe.
Solución: define la PK en el modelo o personaliza la clave con ColumnPrimaryKeyExpression
(admite compuestas).
context.BulkMerge(productos, options => {
options.ColumnPrimaryKeyExpression = x => new { x.Codigo }; // ejemplo de clave externa/compuesta
});
❌ Confundir niveles: FilterList vs BulkMerge
Problema: esperar que FilterList afecte la base de datos.
Solución: FilterList filtra en memoria; BulkMerge
actúa en la BD.
// En memoria (no toca BD)
var nuevos = lista.FilterList(dbIds).Exclude();
// En base de datos (Upsert)
context.BulkMerge(nuevos);
❌ Olvidar async/await en Web/API
Problema: bloqueo de hilos o bajo rendimiento en escenarios web.
Solución: usa la variante asíncrona.
// Async recomendado en Web/API
await context.BulkMergeAsync(productos);
❌ Listas anónimas incompatibles
Problema: propiedades que no coinciden por nombre/tipo con la entidad EF.
Solución: al usar BulkMerge<T>(listaAnónima)
, alinea nombres y tipos.
var anon = new[] { new { Codigo = "A-01", Precio = 59.90m } };
context.BulkMerge<Producto>(anon); // 'Codigo' y 'Precio' deben existir en Producto
❌ Omitir IncludeGraph cuando hay relaciones
Problema: hijos/relaciones no se actualizan o insertan correctamente.
Solución: habilita IncludeGraph
para manejar el grafo completo.
context.BulkMerge(pedidos, options => {
options.IncludeGraph = true; // preserva relaciones y procesa hijos
📚 Recursos útiles
Documentación y enlaces recomendados para profundizar en Entity Framework Extensions y EF Core.
WhereBulkNotContainsFilterList en EF Core con Entity Framework Extensions
— filtra listas para detectar elementos que no existen y preparar BulkInsert/Update/Merge.
📀 ¿Qué sigue? BulkDelete()
En el próximo artículo veremos BulkDelete en EF Core con Entity Framework Extensions, el complemento natural de EF Core BulkMerge para eliminar registros masivamente con alto rendimiento.
¡Gracias por leer! 🙌 Si este contenido te resultó útil, te invitamos a seguir la serie y acompañarnos en el siguiente capítulo.