Как правильно обновить записи в базе данных через ADODB Recordset в 1С?

Программист 1С v8.3 (Обычные формы) IT и автоматизация бизнеса
← На главную

Работа с внешними базами данных через технологию ADODB — стандартная задача для интеграции 1С с другими системами (MS SQL, MySQL, PostgreSQL и др.). Однако при попытке обновить данные программисты часто сталкиваются с тем, что код выполняется без ошибок, но данные в таблице-источнике не меняются, либо обновляется только одна запись вместо группы. В этой статье мы подробно разберем, как правильно настроить объект Recordset, какие параметры выбрать и как избежать распространенных ошибок.

Разбор проблемы: почему Recordset не обновляет данные?

Рассмотрим типичную ситуацию: вы открываете набор записей (Recordset), находите нужные строки, меняете значения полей и вызываете метод Update(). Если обновление не происходит, причина обычно кроется в одном из трех факторов:

  1. Тип курсора и блокировки: По умолчанию многие провайдеры открывают Recordset в режиме «только для чтения» (ReadOnly).
  2. Отсутствие цикла: Метод Update() работает только с текущей записью. Если записей в наборе много, а цикл обхода не прописан, изменения коснутся только первой строки.
  3. Отсутствие ключевых полей: Для успешного обновления Recordset должен содержать первичный ключ (Primary Key) таблицы, чтобы ADO могло идентифицировать строку в базе.

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

Настройка параметров открытия Recordset

Для того чтобы набор записей был доступен для редактирования, необходимо правильно указать параметры в методе Open. Рассмотрим синтаксис:

Recordset.Open(Source, ActiveConnection, CursorType, LockType)

Разберем значения, которые критически важны для записи данных:

Пример правильной инициализации объекта в 1С:


Connection = Новый COMОбъект("ADODB.Connection");
Connection.Open(СтрокаПодключения);

rs = Новый COMОбъект("ADODB.Recordset");
rs.CursorLocation = 3; // adUseClient
rs.LockType = 3;       // adLockOptimistic
rs.CursorType = 1;     // adOpenKeyset

CommandText = "SELECT * FROM MyTable WHERE Status = 'New'";
rs.Open(CommandText, Connection);

Массовое обновление записей в цикле

Частая ошибка новичков — попытка обновить весь набор записей одной командой Update(). Важно понимать: Recordset — это указатель на конкретную строку. Чтобы изменить все отобранные записи, необходимо организовать цикл с переходом по строкам.

Рассмотрим подробнее процесс обновления в цикле:


Пока НЕ rs.EOF() Цикл
    // Устанавливаем новые значения полей для ТЕКУЩЕЙ записи
    rs.Fields("Active").Value = 0;
    rs.Fields("ProcessDate").Value = ТекущаяДата();
    
    // Фиксируем изменения в текущей записи
    rs.Update();
    
    // Переходим к следующей строке (обязательно!)
    rs.MoveNext();
КонецЦикла;

Важный нюанс: В некоторых конфигурациях ADO метод MoveNext() автоматически вызывает Update(), если данные в полях были изменены. Однако явный вызов Update() считается правилом хорошего тона и защищает от неожиданного поведения драйвера базы данных.

Миф о методе Edit()

Многие программисты, пришедшие из мира Delphi или старого Access (DAO), пытаются вызвать метод rs.Edit() перед изменением полей. В ADODB этого метода не существует. Как только вы присваиваете значение свойству Value любого поля, запись автоматически переходит в режим редактирования.

Альтернатива: прямой SQL-запрос UPDATE

Если вам нужно обновить тысячи записей одним и тем же значением, использование Recordset будет крайне неэффективным. На каждую запись 1С будет отправлять отдельный запрос к серверу БД, что создаст огромную нагрузку на сеть.

Проанализируем ситуацию: если логика позволяет, гораздо быстрее выполнить прямой DML-запрос (Data Manipulation Language). Для этого используется объект Command или метод Execute объекта Connection.


// Пример выполнения прямого апдейта
ТекстЗапроса = "UPDATE tbl1 SET Active = 0, UsrID = '" + ТекущийПользовательИД + "' WHERE msgid = " + ИдентификаторСообщения;
Попытка
    Connection.Execute(ТекстЗапроса);
Исключение
    Сообщить("Ошибка выполнения запроса: " + ОписаниеОшибки());
КонецПопытки;

Этот способ работает в десятки раз быстрее, так как вся операция выполняется на стороне сервера базы данных одним транзакционным пакетом.

Особенности работы с типами данных 1С

При передаче данных из 1С в ADO всегда следите за типизацией. Например, уникальный идентификатор (GUID) в 1С является объектом. SQL-сервер его «не поймет», поэтому всегда приводите его к строке: Строка(Ссылка.УникальныйИдентификатор()).

Также будьте внимательны с датами. SQL-сервер часто ожидает дату в формате YYYYMMDD или YYYY-MM-DD HH:MM:SS. Для надежности используйте форматирование:

Формат(ТекущаяДата(), "ДФ=yyyyMMddHHmmss")

Резюме и рекомендации

Подведем итог. Чтобы обновление через Recordset сработало:

  1. Убедитесь, что LockType установлен в значение 3 (Optimistic).
  2. Проверьте, что в вашем SELECT-запросе присутствуют ключевые поля таблицы.
  3. Используйте цикл Пока НЕ rs.EOF() и не забывайте про rs.MoveNext().
  4. Для массовых изменений одного типа всегда отдавайте предпочтение прямому запросу UPDATE через Connection.Execute().

Соблюдение этих простых правил сделает вашу работу с внешними базами данных в 1С стабильной и производительной.

← На главную