Часто в практике программиста 1С возникает задача интеграции со сторонними базами данных. Разберем ситуацию, когда мы успешно подключились к базе данных MS SQL Server через COMОбъект("ADODB.Connection"), считали данные в таблицу значений на форме и теперь нам нужно добавить новые строки из этой таблицы обратно в базу MS SQL. Посмотрим по шагам, как правильно и безопасно реализовать эту процедуру.
Для добавления новой записи в таблицу SQL используется стандартный SQL-запрос INSERT INTO. Чтобы выполнить его из 1С через ADO, необходимо присвоить текст этого запроса свойству объекта команды и вызвать метод выполнения. Проанализируем простейший пример такого запроса:
ТекстЗапроса = "INSERT INTO BROK1.dbo.MN ([MN_DOC_NUMBER], [MN_PRODUCT], [MN_QUANTITY]) VALUES ('2', 'Продукция 1', '3')";
Команда.CommandText = ТекстЗапроса;
Команда.Execute();
Обратите внимание, что создавать объект ADODB.RecordSet для выполнения запросов на изменение данных (INSERT, UPDATE) не требуется. Достаточно просто выполнить Команда.Execute().
Если мы работаем с таблицей значений на форме и хотим записать несколько строк, нам нужно обойти коллекцию в цикле и собрать строку для вставки динамически. Однако важно учитывать, что строка может уже существовать в базе. Рассмотрим, как с помощью конструкции IF NOT EXISTS выполнить вставку только уникальных записей:
Для Каждого Стр Из Таблица Цикл
ТекстТекущейИнструкции = "
|IF NOT EXISTS (SELECT *
| FROM BROK1.dbo.MN
| WHERE MN_DOC_NUMBER = '" + Стр.MN_DOC_NUMBER + "'
| AND MN_PRODUCT = '" + Стр.P_NAME + "'
| AND MN_QUANTITY = '" + Стр.MN_QUANTITY + "')
|INSERT INTO BROK1.dbo.MN ([MN_DOC_NUMBER], [MN_PRODUCT], [MN_QUANTITY])
|VALUES ('" + Стр.MN_DOC_NUMBER + "', '" + Стр.P_NAME + "', '" + Стр.MN_QUANTITY + "')";
Команда.CommandText = ТекстТекущейИнструкции;
Команда.Execute();
КонецЦикла;
Вместо того чтобы при каждой записи проверять каждую строку через сложные SQL-запросы, можно оптимизировать процесс. Выясним способ, как отслеживать состояние строк прямо в таблице значений на форме 1С:
Булево. Назовите ее ЭтоНоваяЗапись и сделайте невидимой для пользователя.Ложь.ПриДобавлении (или ПередНачаломДобавления) для таблицы на форме устанавливайте новой строке значение ЭтоНоваяЗапись = Истина.При нажатии на кнопку записи вам останется только обойти таблицу и выбрать нужные строки:
Для Каждого Стр Из Таблица Цикл
Если Стр.ЭтоНоваяЗапись Тогда
// Формируем текст запроса INSERT и выполняем его
КонецЕсли;
КонецЦикла;
При конкатенации строк (сборке запроса через "плюсы") есть большая опасность столкнуться с ошибкой синтаксиса или SQL-инъекцией. Проанализируем важные нюансы:
Экранирование кавычек. Если пользователь введет в название продукта одинарную кавычку, структура SQL-запроса сломается. Обязательно экранируйте такие символы перед вставкой в текст запроса: СтрЗаменить(Стр.P_NAME, "'", "''"). Еще лучше — использовать параметризованные запросы объекта ADODB.Command.Parameters, где в текст передается знак вопроса ?, а значение добавляется отдельным свойством.
Форматирование чисел и дат. Платформа 1С по умолчанию форматирует числа с неразрывными пробелами (например, 1 000,50). SQL-сервер не поймет такой формат и выдаст ошибку, так как ожидает числа без пробелов и с точкой. Всегда форматируйте числовые значения перед отправкой в запрос: Формат(Стр.MN_QUANTITY, "ЧРД=.; ЧГ=0").
Если мы добавляем несколько строк в цикле, может случиться сбой (например, нарушена уникальность или пропала связь). Чтобы база данных не осталась в наполовину заполненном состоянии, применим механизм транзакций для COM-соединения. Также рассмотрим, как избежать зависших сеансов в MS SQL Server.
Попытка
// Начинаем транзакцию перед циклом
Соединение.BeginTrans();
Для Каждого Стр Из Таблица Цикл
Если Стр.ЭтоНоваяЗапись Тогда
// ... Подготовка и выполнение Command.Execute() ...
КонецЕсли;
КонецЦикла;
// Если все прошло успешно, фиксируем изменения
Соединение.CommitTrans();
Сообщить("Новые записи успешно добавлены!");
Исключение
// В случае ошибки отменяем все изменения
Соединение.RollbackTrans();
Сообщить("Ошибка записи данных: " + ОписаниеОшибки());
КонецПопытки;
// Обязательно закрываем соединение после выполнения всех операций!
Если Соединение <> Неопределено Тогда
Соединение.Close();
Соединение = Неопределено;
КонецЕсли;
Применяя эти методы, вы обеспечите безопасную, стабильную и предсказуемую работу 1С со сторонними таблицами в MS SQL Server.