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