2012-02-10 19 views
13

Ho una domanda che assomiglia a questo:inserimento di massa con LINQ to SQL

using (MyDC TheDC = new MyDC()) 
{ 
    foreach (MyObject TheObject in TheListOfMyObjects) 
    { 
     DBTable TheTable = new DBTable(); 

     TheTable.Prop1 = TheObject.Prop1; 
     ..... 
     TheDC.DBTables.InsertOnSubmit(TheTable); 

    } 
    TheDC.SubmitChanges(); 
} 

Questa query inserisce in pratica una lista nel database utilizzando LINQ to SQL. Ora ho letto online che L2S NON supporta le operazioni di massa. La mia query funziona inserendo ogni elemento alla volta o tutti in una sola scrittura?

Grazie per il chiarimento.

risposta

7

Il termine Bulk Insert si riferisce in genere all'implementazione SqlBulkCopy basata su PC ultra veloce specifica di SQL Server. È costruito sopra IRowsetFastLoad.

Linq-2-SQL non implementa l'inserimento utilizzando questo meccanismo, in condizioni .

Se è necessario eseguire il caricamento in blocco dei dati in SQL Server e devono essere veloci, si consiglia di utilizzare la codifica manuale utilizzando SqlBulkCopy.

Linq-2-SQL tenterà di eseguire alcune ottimizzazioni per accelerare più inserti, tuttavia ancora cadrà corto di molti ORM micro (anche se nessun micro ORM conosco implementare SqlBulkCopy)

3

Genera una singola istruzione di inserimento per ogni record, ma li invierà tutti al server in un singolo batch e verranno eseguiti in un'unica transazione.

Questo è ciò che fa SubmitChanges() all'esterno del ciclo.

Se è stato spostato all'interno, quindi ogni iterazione attraverso il ciclo si sposterà sul server per l'INSERIMENTO e verrà eseguito nella propria transazione.

Non credo che esista un modo per attivare un SQL BULK INSERT.

+0

http://stackoverflow.com/a/1329094/17174 non sono testati L2S inserire perf contro azzimato per un po ', ma ho fatto test di ef vs elegante ... con risultati piuttosto deludente per ef https://gist.github.com/1623514 –

26

ho modificato il codice dal seguente link per essere più efficiente e usarlo nella mia applicazione. È abbastanza comodo perché puoi metterlo in una classe parziale sopra la tua attuale classe autogenerata. Invece di InsertOnSubmit aggiungi entità a un elenco e invece di SubmitChanges chiama YourDataContext.BulkInsertAll(list).

http://www.codeproject.com/Tips/297582/Using-bulk-insert-with-your-linq-to-sql-datacontex

partial void OnCreated() 
{ 
    CommandTimeout = 5 * 60; 
} 

public void BulkInsertAll<T>(IEnumerable<T> entities) 
{       
    using(var conn = new SqlConnection(Connection.ConnectionString)) 
    { 
     conn.Open(); 

     Type t = typeof(T); 

     var tableAttribute = (TableAttribute)t.GetCustomAttributes(
      typeof(TableAttribute), false).Single(); 
     var bulkCopy = new SqlBulkCopy(conn) 
     { 
      DestinationTableName = tableAttribute.Name 
     }; 

     var properties = t.GetProperties().Where(EventTypeFilter).ToArray(); 
     var table = new DataTable(); 

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

private bool EventTypeFilter(System.Reflection.PropertyInfo p) 
{ 
    var attribute = Attribute.GetCustomAttribute(p, 
     typeof(AssociationAttribute)) as AssociationAttribute; 

    if (attribute == null) return true; 
    if (attribute.IsForeignKey == false) return true; 

    return false; 
} 
+0

Utilizzando Linqpad ho dovuto 't.GetProperties(). Dove (EventTypeFilter)' a 't.GetFields()'. Inserito 200k righe in poco più e un minuto! (y) –

+0

Impossibile aggiornare questo abbastanza. Il mio inserto di test di 212 record prendeva 50 secondi, questo lo ridusse a 1,3 secondi. Dovrebbe essere d'aiuto quando inserisco effettivamente record di 10k! – Ian

+0

controllare questo fuori: https://stackoverflow.com/a/21382542/1246870 - ha funzionato bene per me – avs099