La forma más rápida de Insertar en Entity Framework


Estoy buscando la forma más rápida de insertar en Entity Framework.

Estoy preguntando esto debido al escenario en el que tiene 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 conducirá a una transacción incompleta.

Author: Jon Schneider, 2011-05-09

25 answers

A su observación en los comentarios a su pregunta:

"...Cambios de ahorro ( para cada record )..."

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

  • Llame a SaveChanges() una vez después de TODOS los registros.
  • Llame a SaveChanges() después, por ejemplo, de 100 registros.
  • Llamar SaveChanges() después de por ejemplo 100 registros y disponer el contexto y crear uno nuevo.
  • Desactivar 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, sin propiedades de navegación) en la base de datos. Con este código funciona en menos de 3 minutos.

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

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

  • commitCount = 1, recreateContext = false: muchas horas (Esa 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 sec
  • commitCount = 1000000, recreateContext = false: excepción fuera de memoria
  • commitCount = 1, recreateContext = true: más de 10 minutos
  • commitCount = 10, recreateContext = true: 241 seg
  • commitCount = 100, recreateContext = true: 164 seg
  • 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, se detuvo en 50.000 entidades después de 20 minutos.) Este comportamiento no lineal no es tan significativo en todos los demás ensayos.

 857
Author: Slauma,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-05-09 20:39:36

Esta combinación aumenta la velocidad lo suficientemente bien.

context.Configuration.AutoDetectChangesEnabled = false;
context.Configuration.ValidateOnSaveEnabled = false;
 164
Author: arkhivania,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-08-12 15:52:04

La forma más rápida sería usar 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 insert regular o AddRange EntityFramework.BulkInsert vs EF AddRange

El uso es extremadamente simple

context.BulkInsert(hugeAmountOfEntities);
 97
Author: maxlego,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-11-09 07:17:54

Usted debe mirar en el uso de la System.Data.SqlClient.SqlBulkCopy para esto. Aquí está la documentación , y por supuesto hay un montón de tutoriales en línea.

Lo sentimos, sé que estaba buscando una respuesta simple para que EF hiciera lo que desea, pero las operaciones masivas no son realmente para lo que están destinados losMs.

 68
Author: Adam Rackis,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-05-09 17:17:37

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();
        }

    }
}
 46
Author: Irfons,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-01-15 10:56:44

He investigado la respuesta de Slauma (que es impresionante, gracias por el hombre idea), y he reducido el tamaño del lote hasta que he llegado a la velocidad óptima. Mirando los resultados de Slauma:

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

Es visible que hay velocidad aumentar al pasar de 1 a 10, y de 10 a 100, pero de 100 a 1000 la velocidad de inserción está cayendo de nuevo.

Así que me he centrado en lo que está sucediendo cuando reduce el tamaño del lote a un valor entre 10 y 100, y aquí están mis resultados (estoy usando diferentes contenidos de fila, 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

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

 19
Author: Admir Tuzović,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-03-26 08:46:42

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

Entity Framework e insertos masivos lentos

Explora estas áreas y compara el rendimiento:

  1. EF predeterminado (57 minutos para completar la adición de 30.000 registros)
  2. Sustituir por ADO.NET Código (25 segundos para los mismos 30.000)
  3. Context Bloat-Mantener el gráfico de Contexto activo pequeño mediante el uso de un nuevo contexto para cada Unidad de Trabajo (mismo 30.000 inserciones tomar 33 segundos)
  4. Listas grandes-Desactivar AutoDetectChangesEnabled (reduce el tiempo a unos 20 segundos)
  5. Lotes (hasta 16 segundos)
  6. DbTable.AddRange () - (el rendimiento está en el rango 12)
 16
Author: ShaTin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-06-20 03:10:55

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 ayudarlo con ello. Hay algunos por ahí, pero esta vez voy a enchufar descaradamente mi propia biblioteca: https://github.com/MikaelEliasson/EntityFramework.Utilities#batch-insert-entities

El único código que necesitas 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 porque depende de tantos factores, rendimiento de la computadora, red, tamaño del objeto, etc, etc. Las pruebas de rendimiento que he hecho sugieren que las entidades 25k se pueden insertar en alrededor de 10s de la manera estándar en localhost SI optimiza su configuración EF como se menciona en las otras respuestas. Con EFUtilities que toma alrededor de 300ms. Aún más interesante es que he ahorrado alrededor de 3 millones de entidades en menos de 15 segundos utilizando este método, con un promedio de alrededor de 200k entidades por segundo.

El único el problema es, por supuesto, si necesita insertar datos releated. Esto se puede hacer eficazmente en sql Server 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 aplicación para el padre para que pueda establecer las claves foráneas. Esto se puede hacer usando GUIDs o algo así como la generación de id de HiLo.

 14
Author: Mikael Eliasson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-12-19 10:44:11

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

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

Pero en lugar de Dispose() el contexto y recrear, simplemente separo 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 mostrarlos aquí para mantener el código limpio

 14
Author: Stephen Ho,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-07-24 13:06:42

Intente usar un Procedimiento almacenado que obtendrá un XML de los datos que desea insertar.

 7
Author: Maxim,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-05-09 17:18:23

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

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();
    }
}
 4
Author: Sgedda,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-11-25 13:35:24

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

Aquí hay un método de extensión muy simple que hice. Lo uso en par con base de datos primero (no lo pruebo con código primero, pero creo que funciona igual). Cambiar 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 herede de IEnumerable, así:

await context.BulkInsertAllAsync(items);
 4
Author: Guilherme,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-01-22 04:48:05

Estoy buscando la forma más rápida de insertar en Entity Framework

Hay algunas bibliotecas de terceros que soportan Bulk Insert disponibles:

  • Z. EntityFramework.Extensiones (Recomendadas )
  • Efutilidades
  • EntityFramework.BulkInsert

Ver: Entity Framework Bulk Insert library

Tenga cuidado al elegir una biblioteca de inserción masiva. Solo Entity Framework Extensions soporta todo tipo de asociaciones y herencias y es el único que todavía se apoya.


Descargo de responsabilidad : Soy el propietario de Entity Framework Extensions

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

  • A granel SaveChanges
  • Inserto masivo
  • Bulk Delete
  • 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;
});
 3
Author: Jonathan Magnan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-08-18 16:25:46

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

En este escenario puede ir con SqlBulkCopy en ADO.net para resolver su problema

 2
Author: anishMarokey,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-05-09 17:20:03

Aquí hay una comparación de rendimiento entre el uso de Entity Framework y el uso de la clase SqlBulkCopy en un ejemplo realista: Cómo Insertar Objetos Complejos de forma masiva en la base de datos de SQL Server

Como ya han subrayado otros, losMs no están destinados a ser utilizados en operaciones a granel. Ofrecen flexibilidad, separación de preocupaciones y otros beneficios, pero las operaciones masivas (excepto la lectura masiva) no son una de ellas.

 2
Author: Zoran Horvat,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-07-14 14:13:50

Otra opción es utilizar SqlBulkTools disponibles en 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 punto de vista es de mi propia opinión.

 2
Author: Greg R Taylor,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-10-29 23:16:30

Use 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;
}
 2
Author: Amir Saniyan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-06-04 22:06:11

Una de las formas 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

Debe agregar nuget

Install-Package Z.EntityFramework.Extensions

Ahora puede usar el siguiente código

var context = new MyContext();

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

context.BulkInsert(list);
context.BulkSaveChanges();
 2
Author: Reza Jenabi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-10-02 10:05:11

El secreto es insertar en una tabla de clasificación en blanco idéntica. Los insertos se aligeran rápidamente. Luego ejecute un single insert desde eso en su tabla grande principal. Luego trunca la tabla de preparación lista para el siguiente lote.

Ie.

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
 1
Author: Simon Hughes,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-07-18 10:43:30

¿ Alguna vez ha intentado insertar a través de un trabajador en segundo plano o una tarea?

En mi caso, im insertando 7760 registros, distribuidos en 182 tablas diferentes con relaciones de clave foránea ( por NavigationProperties).

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

Solo hago el SaveChanges() después de agregar todas las entidades al contexto. (para garantizar la integridad de los datos)

 1
Author: Rafael A. M. S.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-05-27 20:19:58

Todas las soluciones escritas aquí no ayudan porque cuando haces SaveChanges(), las sentencias insert se envían a la base de datos una por una, así es como funciona Entity.

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

Tienes que usar BulkInsert, aquí está el enlace: https://efbulkinsert.codeplex.com /

El tiempo de inserción se redujo de 5-6 minutos a 10-12 segundos al usarlo.

 1
Author: Aleksa,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-10-01 13:05:03

Puede usar la biblioteca Bulk package. La versión Bulk Insert 1.0.0 se utiliza en proyectos que tienen Entity framework > = 6.0.0 .

Puede encontrar más descripción aquí- Código fuente de Bulkoperation

 1
Author: Mohd Nadeem,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-04-17 13:54:31

[NUEVA SOLUCIÓN PARA POSTGRESQL] Oye, sé que es un post bastante viejo, pero recientemente me he encontrado con 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 libre adecuada para hacerlo en esta base de datos. Sólo he encontrado este ayudante: https://bytefish.de/blog/postgresql_bulk_insert / que también está en Nuget. He escrito un pequeño mapeador, que asigna automáticamente las propiedades de la Entidad de forma Marco:

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 (tenía entidad nombrada Empresa):

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

Mostré un ejemplo con transaction, pero también se puede hacer con la conexión normal recuperada del contexto. undertakingsToAdd es enumerable de los registros de entidades normales, que quiero BulkInsert en DB.

Esta solución, a la que tengo después de unas horas de investigación y tratando, es como se podía esperar mucho más rápido y finalmente fácil de usar y gratis! Realmente te aconsejo que uses esto solución, no solo por las razones mencionadas anteriormente, sino también porque es la única con la que no tuve problemas con Postgresql en sí, muchas otras soluciones funcionan perfectamente, por ejemplo, con SQLServer.

 1
Author: Michał Pilarek,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-09-05 21:03:27

Pero, para más de (+4000) inserciones recomiendo usar procedimiento almacenado. adjunto el tiempo transcurrido. Hice insertado 11.788 filas en 20"introduzca la descripción de la imagen aquí

Eso es el código

 public void InsertDataBase(MyEntity entity)
    {
        repository.Database.ExecuteSqlCommand("sp_mystored " +
                "@param1, @param2"
                 new SqlParameter("@param1", entity.property1),
                 new SqlParameter("@param2", entity.property2));
    }
 0
Author: Marinpietri,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-11-20 00:54:00

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

Desde su código c# pase insertar datos como xml.

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

object id_application = db.ExecuteScalar("procSaveApplication", xml)
 0
Author: arun tiwari,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-01-07 03:33:19