Функциональность многострочного добавления данных
Glossary Item Box
Общие сведения
Начиная с версии 7.12.4 вbpm'online появилась функциональность многострочной вставки. Она доступна на уровне класса Insert и ее работа определяется методом Values().
При вызове метода Values() все последующие вызовы Set() попадают в новый экземпляр ColumnsValues. При построении запроса, если в коллекции ColumnsValuesCollection встречается более одного набора данных, то будет построен запрос с несколькими блоками Values().
Например:
new Insert(UserConnection) .Into("Table") .Values() .Set("Column1", Column.Const(1)) .Set("Column2", Column.Const(1)) .Set("Column3", Column.Const(1)) .Values() .Set("Column1", Column.Const(2)) .Set("Column2", Column.Const(2)) .Set("Column3", Column.Const(2)) .Values() .Set("Column1", Column.Const(3)) .Set("Column2", Column.Const(3)) .Set("Column3", Column.Const(3)) .Execute();
В результате будет сформирован следующий SQL-запрос:
--Для MSSQL или PostgreSQL INSERT INTO [dbo].[Table] (Column1, Column2, Column3) VALUES (1, 1, 1), (2, 2, 2), (3, 3, 3) -- Для Oracle INSERT ALL into Table (column1, column2, column3) values (1, 1, 1) into Table (column1, column2, column3) values (2, 2, 2) into Table (column1, column2, column3) values (3, 3, 3) SELECT * FROM dual
Особенности использования
1. При использовании Column.Parameter в выражении Set() необходимо помнить про ограничение 2100 параметров в MS SQL.
2. Класс Insert не может самостоятельно разбивать запрос на несколько, если в нем находится больше параметров, чем нужно. Разбиение на несколько запросов должно быть реализовано разработчиком. Например:
IEnumerable<IEnumerable<ImportEntity>> GetImportEntitiesChunks(IEnumerable<ImportEntity> entities, IEnumerable<ImportColumn> keyColumns) { var entitiesList = entities.ToList(); var columnsList = keyColumns.ToList(); var maxParamsPerChunk = Math.Abs(MaxParametersCountPerQueryChunk / columnsList.Count + 1); var chunksCount = (int)Math.Ceiling(entitiesList.Count / (double)maxParamsPerChunk); return entitiesList.SplitOnParts(chunksCount); } var entitiesList = GetImportEntitiesChunks(entities, importColumns); entitiesList.AsParallel().AsOrdered() .ForAll(entitiesBatch => { try { var insertQuery = GetBufferedImportEntityInsertQuery(); foreach (var importEntity in entitiesBatch) { insertQuery.Values(); SetBufferedImportEntityInsertColumnValues(importEntity, insertQuery, importColumns); insertQuery.Set("ImportSessionId", Column.Const(importSessionId)); } insertQuery.Execute(); } catch (Exception e) { //... } });
3. Класс Insert() не проводит валидацию на соответствие количества колонок и количества условий Set(). Например, есть результирующий SQL-запрос:
INSERT INTO [dbo].[Table] (Column1, Column2, Column3) Values (1, 2), (1, 2, 3)
В таком случае возникнет исключение на уровне работы СУБД. Подобная валидация не лежит в зоне ответственности класса Insert и зависит только от разработчика.