Объемная вставка с 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();
}

Этот запрос в основном вставляет список в базу данных, используя linq-to-sql. Теперь я читал онлайн, что L2S НЕ поддерживает массовые операции. Выполняется ли мой запрос, вставляя каждый элемент за раз или все из них в одной записи?

Спасибо за разъяснение.

Ответы

Ответ 1

Термин Bulk Insert обычно относится к специфической сверхбыстрой bcp SQL Server, основанной на SqlBulkCopy. Он построен поверх IRowsetFastLoad.

Linq-2-SQL не реализует вставку с использованием этого механизма в любых условиях.

Если вам нужно загружать данные на большой объем в SQL Server и нужно быстро, я бы рекомендовал ручное кодирование с использованием SqlBulkCopy.

Linq-2-SQL попытается выполнить некоторые оптимизации для ускорения работы нескольких вставок, однако он по-прежнему будет отставать от многих микро ORM (даже если никакие микро ORM, которые я знаю о реализации SqlBulkCopy)

Ответ 2

Я изменил код из следующей ссылки, чтобы быть более эффективным и использовать его в своем приложении. Это довольно удобно, потому что вы можете просто поместить его в частичный класс поверх своего текущего автогенерированного класса. Вместо InsertOnSubmit добавить объекты в список, а вместо SubmitChanges вызвать 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;
}

Ответ 3

Он будет генерировать один оператор insert для каждой записи, но отправит их все на сервер в одну партию и запустит за одну транзакцию.

Это то, что делает SubmitChanges() вне цикла.

Если вы переместили его внутрь, каждая итерация через цикл выйдет на сервер для INSERT и запустит в нем собственную транзакцию.

Я не верю, что есть способ отключить SQL BULK INSERT.