update registro query insertar framework eliminar ejemplo delete datos con buscar c# sql entity-framework

c# - registro - La manera más rápida de insertar en Entity Framework



insertar registro entity framework c# (25)

Estoy buscando la forma más rápida de inserción en Entity Framework.

Estoy preguntando esto debido al escenario en el que tienes un TransactionScope activo y la inserción es enorme (4000+). Potencialmente, puede durar más de 10 minutos (tiempo de espera predeterminado de las transacciones), y esto llevará a una transacción incompleta.


Estoy buscando la forma más rápida de inserción en Entity Framework

Hay algunas bibliotecas de terceros que admiten Bulk Insert disponibles:

  • Z.EntityFramework.Extensions ( Recomendado )
  • EFUTILIDADES
  • EntityFramework.BulkInsert

Ver: Entity Framework Bulk insert library

Tenga cuidado al elegir una biblioteca de inserciones masivas. Solo Entity Framework Extensions admite todo tipo de asociaciones y herencias, y es la única que aún se admite.

Descargo de responsabilidad : soy el propietario de Entity Framework Extensions

Esta biblioteca le permite realizar todas las operaciones masivas que necesita para sus escenarios:

  • Guardar grandes cambios
  • Inserto a granel
  • Eliminar a granel
  • Actualización masiva
  • Fusión masiva

Ejemplo

// Easy to use context.BulkSaveChanges(); // Easy to customize context.BulkSaveChanges(bulk => bulk.BatchSize = 100); // Perform Bulk Operations context.BulkDelete(customers); context.BulkInsert(customers); context.BulkUpdate(customers); // Customize Primary Key context.BulkMerge(customers, operation => { operation.ColumnPrimaryKeyExpression = customer => customer.Code; });


¿Alguna vez has tratado de insertar a través de un trabajador de fondo o una tarea?

En mi caso, estoy insertando registros 7760, distribuidos en 182 tablas diferentes con relaciones de clave externa (por NavigationProperties).

Sin la tarea, tardó 2 minutos y medio. Dentro de una tarea ( Task.Factory.StartNew(...)), tomó 15 segundos.

Solo estoy haciendo lo siguiente SaveChanges()después de agregar todas las entidades al contexto. (para garantizar la integridad de los datos)


A continuación, se presenta una comparación de rendimiento entre el uso de Entity Framework y el uso de la clase SqlBulkCopy en un ejemplo realista: Cómo agregar de forma masiva objetos complejos en la base de datos de SQL Server

Como otros ya enfatizaron, los ORM no deben utilizarse en operaciones a granel. Ofrecen flexibilidad, separación de inquietudes y otros beneficios, pero las operaciones masivas (excepto la lectura masiva) no son una de ellas.


A su comentario en los comentarios a su pregunta:

"... SavingChanges ( para cada registro ) ..."

¡Eso es lo peor que puedes hacer! Llamar a SaveChanges() para cada registro ralentiza extremadamente las inserciones masivas. Haría algunas pruebas simples que probablemente mejorarán el rendimiento:

  • Llame a SaveChanges() una vez después de TODOS los registros.
  • Llame a SaveChanges() después de, por ejemplo, 100 registros.
  • Llame a SaveChanges() después de, por ejemplo, 100 registros, elimine el contexto y cree uno nuevo.
  • Deshabilitar la detección de cambios

Para inserciones a granel estoy trabajando y experimentando con un patrón como este:

using (TransactionScope scope = new TransactionScope()) { MyDbContext context = null; try { context = new MyDbContext(); context.Configuration.AutoDetectChangesEnabled = false; int count = 0; foreach (var entityToInsert in someCollectionOfEntitiesToInsert) { ++count; context = AddToContext(context, entityToInsert, count, 100, true); } context.SaveChanges(); } finally { if (context != null) context.Dispose(); } scope.Complete(); } private MyDbContext AddToContext(MyDbContext context, Entity entity, int count, int commitCount, bool recreateContext) { context.Set<Entity>().Add(entity); if (count % commitCount == 0) { context.SaveChanges(); if (recreateContext) { context.Dispose(); context = new MyDbContext(); context.Configuration.AutoDetectChangesEnabled = false; } } return context; }

Tengo un programa de prueba que inserta 560,000 entidades (9 propiedades escalares, no propiedades de navegación) en el DB. Con este código funciona en menos de 3 minutos.

Para el rendimiento, es importante llamar a SaveChanges() después de "muchos" registros ("muchos" alrededor de 100 o 1000). También mejora el rendimiento para disponer el contexto después de SaveChanges y crear uno nuevo. Esto borra el contexto de todos los entits, SaveChanges no hace eso, las entidades todavía están vinculadas al contexto en el estado Unchanged . Es el creciente tamaño de las entidades vinculadas en el contexto lo que ralentiza la inserción paso a paso. Por lo tanto, es útil aclararlo después de algún tiempo.

Aquí están algunas medidas para mis 560.000 entidades:

  • commitCount = 1, recreateContext = false: muchas horas (ese es su procedimiento actual)
  • commitCount = 100, recreateContext = false: más de 20 minutos
  • commitCount = 1000, recreateContext = false: 242 seg.
  • commitCount = 10000, recreateContext = false: 202 seg
  • commitCount = 100000, recreateContext = false: 199 seg
  • commitCount = 1000000, recreateContext = false: excepción de memoria insuficiente
  • commitCount = 1, recreateContext = true: más de 10 minutos
  • commitCount = 10, recreateContext = true: 241 sec
  • commitCount = 100, recreateContext = true: 164 segundos
  • commitCount = 1000, recreateContext = true: 191 sec

El comportamiento en la primera prueba anterior es que el rendimiento es muy no lineal y disminuye extremadamente con el tiempo. ("Muchas horas" es una estimación, nunca terminé esta prueba, me detuve en 50.000 entidades después de 20 minutos). Este comportamiento no lineal no es tan significativo en todas las demás pruebas.


Como otras personas han dicho, SqlBulkCopy es la forma de hacerlo si desea un rendimiento de inserción realmente bueno.

Es un poco engorroso de implementar, pero hay bibliotecas que pueden ayudarte con eso. Hay algunos por ahí, pero esta vez me voy a desconectar descaradamente de mi propia biblioteca: https://github.com/MikaelEliasson/EntityFramework.Utilities#batch-insert-entities

El único código que necesitarías es:

using (var db = new YourDbContext()) { EFBatchOperation.For(db, db.BlogPosts).InsertAll(list); }

Entonces, ¿cuánto más rápido es? Muy difícil de decir, ya que depende de muchos factores, el rendimiento del equipo, la red, el tamaño del objeto, etc. Las pruebas de rendimiento que he realizado sugieren que se pueden insertar entidades de 25k aproximadamente a 10 segundos de la manera estándar en localhost SI optimiza su configuración de EF como mencionado en las otras respuestas. Con EFUtilidades que lleva unos 300ms. Aún más interesante es que he guardado alrededor de 3 millones de entidades en menos de 15 segundos con este método, con un promedio de alrededor de 200k entidades por segundo.

El único problema es, por supuesto, si necesita insertar datos repetidos. Esto se puede hacer de manera eficiente en el servidor SQL utilizando el método anterior, pero requiere que tenga una estrategia de generación de ID que le permita generar ID en el código de la aplicación para el padre para que pueda establecer las claves externas. Esto se puede hacer usando GUIDs o algo así como la generación de identificación HiLo.


Debería considerar el uso de System.Data.SqlClient.SqlBulkCopy para esto. Aquí está la documentation y, por supuesto, hay muchos tutoriales en línea.

Lo siento, sé que estaba buscando una respuesta simple para que EF haga lo que quiere, pero las operaciones en masa no son realmente para lo que están diseñados los ORM.


El secreto es insertar en una tabla de preparación en blanco idéntica. Las inserciones son de aclarado rápido. A continuación, ejecute una sola inserción de eso en su gran mesa principal. Luego trunca la tabla de preparación lista para el siguiente lote.

es decir.

insert into some_staging_table using Entity Framework. -- Single insert into main table (this could be a tiny stored proc call) insert into some_main_already_large_table (columns...) select (columns...) from some_staging_table truncate table some_staging_table


Esta combinación aumenta la velocidad suficientemente bien.

context.Configuration.AutoDetectChangesEnabled = false; context.Configuration.ValidateOnSaveEnabled = false;


Estoy de acuerdo con Adam Rackis. SqlBulkCopy es la forma más rápida de transferir registros masivos de una fuente de datos a otra. Usé esto para copiar registros de 20K y tomó menos de 3 segundos. Echa un vistazo al siguiente ejemplo.

public static void InsertIntoMembers(DataTable dataTable) { using (var connection = new SqlConnection(@"data source=;persist security info=True;user id=;password=;initial catalog=;MultipleActiveResultSets=True;App=EntityFramework")) { SqlTransaction transaction = null; connection.Open(); try { transaction = connection.BeginTransaction(); using (var sqlBulkCopy = new SqlBulkCopy(connection, SqlBulkCopyOptions.TableLock, transaction)) { sqlBulkCopy.DestinationTableName = "Members"; sqlBulkCopy.ColumnMappings.Add("Firstname", "Firstname"); sqlBulkCopy.ColumnMappings.Add("Lastname", "Lastname"); sqlBulkCopy.ColumnMappings.Add("DOB", "DOB"); sqlBulkCopy.ColumnMappings.Add("Gender", "Gender"); sqlBulkCopy.ColumnMappings.Add("Email", "Email"); sqlBulkCopy.ColumnMappings.Add("Address1", "Address1"); sqlBulkCopy.ColumnMappings.Add("Address2", "Address2"); sqlBulkCopy.ColumnMappings.Add("Address3", "Address3"); sqlBulkCopy.ColumnMappings.Add("Address4", "Address4"); sqlBulkCopy.ColumnMappings.Add("Postcode", "Postcode"); sqlBulkCopy.ColumnMappings.Add("MobileNumber", "MobileNumber"); sqlBulkCopy.ColumnMappings.Add("TelephoneNumber", "TelephoneNumber"); sqlBulkCopy.ColumnMappings.Add("Deleted", "Deleted"); sqlBulkCopy.WriteToServer(dataTable); } transaction.Commit(); } catch (Exception) { transaction.Rollback(); } } }


He hecho una extensión genérica del ejemplo de @Slauma s arriba;

public static class DataExtensions { public static DbContext AddToContext<T>(this DbContext context, object entity, int count, int commitCount, bool recreateContext, Func<DbContext> contextCreator) { context.Set(typeof(T)).Add((T)entity); if (count % commitCount == 0) { context.SaveChanges(); if (recreateContext) { context.Dispose(); context = contextCreator.Invoke(); context.Configuration.AutoDetectChangesEnabled = false; } } return context; } }

Uso:

public void AddEntities(List<YourEntity> entities) { using (var transactionScope = new TransactionScope()) { DbContext context = new YourContext(); int count = 0; foreach (var entity in entities) { ++count; context = context.AddToContext<TenancyNote>(entity, count, 100, true, () => new YourContext()); } context.SaveChanges(); transactionScope.Complete(); } }


He investigado la respuesta de Slauma (lo cual es increíble, gracias por la idea) y reduje el tamaño del lote hasta que alcancé la velocidad óptima. Mirando los resultados de Slauma:

  • commitCount = 1, recreateContext = true: más de 10 minutos
  • commitCount = 10, recreateContext = true: 241 sec
  • commitCount = 100, recreateContext = true: 164 segundos
  • commitCount = 1000, recreateContext = true: 191 sec

Es visible que hay un aumento de velocidad cuando se mueve de 1 a 10, y de 10 a 100, pero de 100 a 1000 la velocidad de inserción está cayendo nuevamente.

Así que me he centrado en lo que está sucediendo cuando reduce el tamaño del lote al valor en algún lugar entre 10 y 100, y aquí están mis resultados (estoy usando diferentes contenidos de filas, por lo que mis tiempos son de diferente valor):

Quantity | Batch size | Interval 1000 1 3 10000 1 34 100000 1 368 1000 5 1 10000 5 12 100000 5 133 1000 10 1 10000 10 11 100000 10 101 1000 20 1 10000 20 9 100000 20 92 1000 27 0 10000 27 9 100000 27 92 1000 30 0 10000 30 9 100000 30 92 1000 35 1 10000 35 9 100000 35 94 1000 50 1 10000 50 10 100000 50 106 1000 100 1 10000 100 14 100000 100 141

Según mis resultados, el óptimo real está alrededor del valor de 30 para el tamaño del lote. Es menos que 10 y 100. El problema es que no tengo idea de por qué 30 es óptimo, ni podría haber encontrado ninguna explicación lógica para ello.


Intente utilizar un procedimiento almacenado que obtenga un XML de los datos que desea insertar.


La forma más rápida sería usar la extensión de inserción masiva , que desarrollé.

Utiliza SqlBulkCopy y datareader personalizado para obtener el máximo rendimiento. Como resultado, es más de 20 veces más rápido que usar la inserción regular o AddRange

el uso es extremadamente simple

context.BulkInsert(hugeAmountOfEntities);


Otra opción es usar SqlBulkTools disponibles de Nuget. Es muy fácil de usar y tiene algunas características poderosas.

Ejemplo:

var bulk = new BulkOperations(); var books = GetBooks(); using (TransactionScope trans = new TransactionScope()) { using (SqlConnection conn = new SqlConnection(ConfigurationManager .ConnectionStrings["SqlBulkToolsTest"].ConnectionString)) { bulk.Setup<Book>() .ForCollection(books) .WithTable("Books") .AddAllColumns() .BulkInsert() .Commit(conn); } trans.Complete(); }

Vea la documentación para más ejemplos y uso avanzado. Descargo de responsabilidad: Soy el autor de esta biblioteca y cualquier opinión es de mi propia opinión.


Recomendaría este artículo sobre cómo hacer inserciones masivas utilizando EF.

Entity Framework y INSERTs a granel lento

Explora estas áreas y compara el rendimiento:

  1. EF predeterminado (57 minutos para completar la adición de 30,000 registros)
  2. Reemplazo con código ADO.NET (25 segundos para esos mismos 30,000)
  3. Bloqueo de contexto: mantenga pequeño el gráfico de contexto activo utilizando un nuevo contexto para cada unidad de trabajo (las mismas 30,000 inserciones toman 33 segundos)
  4. Listas grandes: desactiva AutoDetectChangesEnabled (reduce el tiempo a unos 20 segundos)
  5. Dosificación (hasta 16 segundos)
  6. DbTable.AddRange () - (el rendimiento está en el rango 12)

Sé que esta es una pregunta muy antigua, pero un tipo aquí dijo que desarrolló un método de extensión para usar inserciones masivas con EF, y cuando lo comprobé, descubrí que la biblioteca cuesta $ 599 hoy (para un desarrollador). Tal vez tenga sentido para toda la biblioteca, sin embargo, solo para la inserción masiva es demasiado.

Aquí hay un método de extensión muy simple que hice. Lo uso en par con la base de datos primero (no lo he probado con el código primero, pero creo que funciona igual). Cambie YourEntities con el nombre de su contexto:

public partial class YourEntities : DbContext { public async Task BulkInsertAllAsync<T>(IEnumerable<T> entities) { using (var conn = new SqlConnection(Database.Connection.ConnectionString)) { conn.Open(); Type t = typeof(T); var bulkCopy = new SqlBulkCopy(conn) { DestinationTableName = GetTableName(t) }; var table = new DataTable(); var properties = t.GetProperties().Where(p => p.PropertyType.IsValueType || p.PropertyType == typeof(string)); foreach (var property in properties) { Type propertyType = property.PropertyType; if (propertyType.IsGenericType && propertyType.GetGenericTypeDefinition() == typeof(Nullable<>)) { propertyType = Nullable.GetUnderlyingType(propertyType); } table.Columns.Add(new DataColumn(property.Name, propertyType)); } foreach (var entity in entities) { table.Rows.Add( properties.Select(property => property.GetValue(entity, null) ?? DBNull.Value).ToArray()); } bulkCopy.BulkCopyTimeout = 0; await bulkCopy.WriteToServerAsync(table); } } public void BulkInsertAll<T>(IEnumerable<T> entities) { using (var conn = new SqlConnection(Database.Connection.ConnectionString)) { conn.Open(); Type t = typeof(T); var bulkCopy = new SqlBulkCopy(conn) { DestinationTableName = GetTableName(t) }; var table = new DataTable(); var properties = t.GetProperties().Where(p => p.PropertyType.IsValueType || p.PropertyType == typeof(string)); foreach (var property in properties) { Type propertyType = property.PropertyType; if (propertyType.IsGenericType && propertyType.GetGenericTypeDefinition() == typeof(Nullable<>)) { propertyType = Nullable.GetUnderlyingType(propertyType); } table.Columns.Add(new DataColumn(property.Name, propertyType)); } foreach (var entity in entities) { table.Rows.Add( properties.Select(property => property.GetValue(entity, null) ?? DBNull.Value).ToArray()); } bulkCopy.BulkCopyTimeout = 0; bulkCopy.WriteToServer(table); } } public string GetTableName(Type type) { var metadata = ((IObjectContextAdapter)this).ObjectContext.MetadataWorkspace; var objectItemCollection = ((ObjectItemCollection)metadata.GetItemCollection(DataSpace.OSpace)); var entityType = metadata .GetItems<EntityType>(DataSpace.OSpace) .Single(e => objectItemCollection.GetClrType(e) == type); var entitySet = metadata .GetItems<EntityContainer>(DataSpace.CSpace) .Single() .EntitySets .Single(s => s.ElementType.Name == entityType.Name); var mapping = metadata.GetItems<EntityContainerMapping>(DataSpace.CSSpace) .Single() .EntitySetMappings .Single(s => s.EntitySet == entitySet); var table = mapping .EntityTypeMappings.Single() .Fragments.Single() .StoreEntitySet; return (string)table.MetadataProperties["Table"].Value ?? table.Name; } }

Puedes usar eso contra cualquier colección que se herede de IEnumerable , así:

await context.BulkInsertAllAsync(items);


Según mi conocimiento, no no BulkInsert en EntityFramework para aumentar el rendimiento de las inserciones enormes.

En este escenario, puedes ir con documentation en ADO.net para resolver tu problema


Una de las maneras más rápidas de guardar una lista debe aplicar el siguiente código

context.Configuration.AutoDetectChangesEnabled = false; context.Configuration.ValidateOnSaveEnabled = false;

AutoDetectChangesEnabled = false

Add, AddRange & SaveChanges: no detecta cambios.

ValidateOnSaveEnabled = false;

No detecta el rastreador de cambios.

Usted debe agregar nuget

Install-Package Z.EntityFramework.Extensions

Ahora puedes usar el siguiente código

var context = new MyContext(); context.Configuration.AutoDetectChangesEnabled = false; context.Configuration.ValidateOnSaveEnabled = false; context.BulkInsert(list); context.BulkSaveChanges();


Utilice SqlBulkCopy :

void BulkInsert(GpsReceiverTrack[] gpsReceiverTracks) { if (gpsReceiverTracks == null) { throw new ArgumentNullException(nameof(gpsReceiverTracks)); } DataTable dataTable = new DataTable("GpsReceiverTracks"); dataTable.Columns.Add("ID", typeof(int)); dataTable.Columns.Add("DownloadedTrackID", typeof(int)); dataTable.Columns.Add("Time", typeof(TimeSpan)); dataTable.Columns.Add("Latitude", typeof(double)); dataTable.Columns.Add("Longitude", typeof(double)); dataTable.Columns.Add("Altitude", typeof(double)); for (int i = 0; i < gpsReceiverTracks.Length; i++) { dataTable.Rows.Add ( new object[] { gpsReceiverTracks[i].ID, gpsReceiverTracks[i].DownloadedTrackID, gpsReceiverTracks[i].Time, gpsReceiverTracks[i].Latitude, gpsReceiverTracks[i].Longitude, gpsReceiverTracks[i].Altitude } ); } string connectionString = (new TeamTrackerEntities()).Database.Connection.ConnectionString; using (var connection = new SqlConnection(connectionString)) { connection.Open(); using (var transaction = connection.BeginTransaction()) { using (var sqlBulkCopy = new SqlBulkCopy(connection, SqlBulkCopyOptions.TableLock, transaction)) { sqlBulkCopy.DestinationTableName = dataTable.TableName; foreach (DataColumn column in dataTable.Columns) { sqlBulkCopy.ColumnMappings.Add(column.ColumnName, column.ColumnName); } sqlBulkCopy.WriteToServer(dataTable); } transaction.Commit(); } } return; }


Dispose() contexto Dispose() crea problemas si las entidades que Add() dependen de otras entidades precargadas (por ejemplo, propiedades de navegación) en el contexto

Utilizo un concepto similar para mantener mi contexto pequeño para lograr el mismo rendimiento

Pero en lugar de Dispose() el contexto y recrear, simplemente SaveChanges() las entidades que ya SaveChanges()

public void AddAndSave<TEntity>(List<TEntity> entities) where TEntity : class { const int CommitCount = 1000; //set your own best performance number here int currentCount = 0; while (currentCount < entities.Count()) { //make sure it don''t commit more than the entities you have int commitCount = CommitCount; if ((entities.Count - currentCount) < commitCount) commitCount = entities.Count - currentCount; //e.g. Add entities [ i = 0 to 999, 1000 to 1999, ... , n to n+999... ] to conext for (int i = currentCount; i < (currentCount + commitCount); i++) _context.Entry(entities[i]).State = System.Data.EntityState.Added; //same as calling _context.Set<TEntity>().Add(entities[i]); //commit entities[n to n+999] to database _context.SaveChanges(); //detach all entities in the context that committed to database //so it won''t overload the context for (int i = currentCount; i < (currentCount + commitCount); i++) _context.Entry(entities[i]).State = System.Data.EntityState.Detached; currentCount += commitCount; } }

envuélvalo con try catch y TrasactionScope() si lo necesita, no los muestra aquí para mantener el código limpio


Todas las soluciones escritas aquí no ayudan porque al hacer SaveChanges (), las declaraciones de inserción se envían a la base de datos una por una, así funciona la Entidad

Y si su viaje a la base de datos y viceversa es de 50 ms por ejemplo, entonces el tiempo necesario para insertar es el número de registros x 50 ms.

Debe utilizar BulkInsert, aquí está el enlace: https://efbulkinsert.codeplex.com/

Obtuve el tiempo de inserción reducido de 5-6 minutos a 10-12 segundos al usarlo.


Utilice el procedimiento almacenado que toma datos de entrada en forma de xml para insertar datos.

Desde su código c #, inserte los datos como xml.

por ejemplo, en c #, la sintaxis sería así:

object id_application = db.ExecuteScalar("procSaveApplication", xml)


Pero, para más de (+4000) inserciones, recomiendo usar un procedimiento almacenado. Adjunto el tiempo transcurrido. Lo inserté 11.788 filas en 20 "

eso es código

public void InsertDataBase(MyEntity entity) { repository.Database.ExecuteSqlCommand("sp_mystored " + "@param1, @param2" new SqlParameter("@param1", entity.property1), new SqlParameter("@param2", entity.property2)); }



[NUEVA SOLUCIÓN PARA POSTGRESQL] Oye, sé que es una publicación bastante antigua, pero recientemente tuve un problema similar, pero estábamos usando Postgresql. Quería usar bulkinsert eficaz, lo que resultó ser bastante difícil. No he encontrado ninguna biblioteca gratuita adecuada para hacerlo en este DB. Solo he encontrado este ayudante: https://bytefish.de/blog/postgresql_bulk_insert/ que también está en Nuget. He escrito un pequeño asignador, que asignó automáticamente las propiedades de la forma en que Entity Framework:

public static PostgreSQLCopyHelper<T> CreateHelper<T>(string schemaName, string tableName) { var helper = new PostgreSQLCopyHelper<T>("dbo", "/"" + tableName + "/""); var properties = typeof(T).GetProperties(); foreach(var prop in properties) { var type = prop.PropertyType; if (Attribute.IsDefined(prop, typeof(KeyAttribute)) || Attribute.IsDefined(prop, typeof(ForeignKeyAttribute))) continue; switch (type) { case Type intType when intType == typeof(int) || intType == typeof(int?): { helper = helper.MapInteger("/"" + prop.Name + "/"", x => (int?)typeof(T).GetProperty(prop.Name).GetValue(x, null)); break; } case Type stringType when stringType == typeof(string): { helper = helper.MapText("/"" + prop.Name + "/"", x => (string)typeof(T).GetProperty(prop.Name).GetValue(x, null)); break; } case Type dateType when dateType == typeof(DateTime) || dateType == typeof(DateTime?): { helper = helper.MapTimeStamp("/"" + prop.Name + "/"", x => (DateTime?)typeof(T).GetProperty(prop.Name).GetValue(x, null)); break; } case Type decimalType when decimalType == typeof(decimal) || decimalType == typeof(decimal?): { helper = helper.MapMoney("/"" + prop.Name + "/"", x => (decimal?)typeof(T).GetProperty(prop.Name).GetValue(x, null)); break; } case Type doubleType when doubleType == typeof(double) || doubleType == typeof(double?): { helper = helper.MapDouble("/"" + prop.Name + "/"", x => (double?)typeof(T).GetProperty(prop.Name).GetValue(x, null)); break; } case Type floatType when floatType == typeof(float) || floatType == typeof(float?): { helper = helper.MapReal("/"" + prop.Name + "/"", x => (float?)typeof(T).GetProperty(prop.Name).GetValue(x, null)); break; } case Type guidType when guidType == typeof(Guid): { helper = helper.MapUUID("/"" + prop.Name + "/"", x => (Guid)typeof(T).GetProperty(prop.Name).GetValue(x, null)); break; } } } return helper; }

Lo uso de la siguiente manera (tuve una entidad llamada Compromiso):

var undertakingHelper = BulkMapper.CreateHelper<Model.Undertaking>("dbo", nameof(Model.Undertaking)); undertakingHelper.SaveAll(transaction.UnderlyingTransaction.Connection as Npgsql.NpgsqlConnection, undertakingsToAdd));

Mostré un ejemplo con una transacción, pero también se puede hacer con una conexión normal recuperada del contexto. undertakingsToAdd es enumerable de los registros de la entidad normal, que quiero insertar de forma masiva en la base de datos.

¡Esta solución, que obtuve después de algunas horas de investigación e intento, es como podría esperarse mucho más rápido y, finalmente, fácil de usar y gratis! Realmente le aconsejo que use esta solución, no solo por las razones mencionadas anteriormente, sino también porque es la única con la que no tuve problemas con Postgresql, muchas otras soluciones funcionan perfectamente, por ejemplo, con SqlServer.