Как правильно выгрузить данные регистра накопления во внешнюю базу MSSQL?

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

При интеграции 1С с внешними системами на базе MSSQL программисты часто сталкиваются с фундаментальным различием между объектными и необъектными данными. Если для справочников или документов у нас есть уникальный идентификатор (GUID), по которому легко найти, обновить или удалить запись в сторонней базе, то с регистрами накопления ситуация иная. Разберем подробно, как организовать выгрузку данных регистра накопления, например, ВзаиморасчетыСКонтрагентами, и как обеспечить уникальность этих записей во внешней таблице.

Понятие необъектных данных и проблема идентификации

Прежде всего, проанализируем структуру данных. В 1С объекты делятся на ссылочные (справочники, документы) и нессылочные (регистры, табличные части). У регистров накопления нет встроенного поля Ссылка. Это означает, что «из коробки» у записи нет единого ГУИДа.

Многие начинающие разработчики пытаются найти способ получить ГУИД для строки регистра, но его не существует в привычном виде. Вместо него используется составной ключ уникальности. Чтобы корректно работать с данными во внешней базе, нам нужно воспроизвести этот ключ в структуре таблицы MSSQL. Рассмотрим подробнее, из чего он состоит на уровне СУБД:

  1. Период (_Period) — дата и время совершения движения.
  2. Регистратор (_RecorderTRef и _RecorderRRef) — ссылка на документ, который создал запись. В SQL она состоит из идентификатора типа таблицы и самого бинарного кода ссылки.
  3. Номер строки (_LineNo) — порядковый номер движения в рамках одного документа-регистратора.

Только комбинация этих полей гарантирует уникальность каждой конкретной записи в физической таблице регистра.

Проектирование таблицы во внешнем источнике данных

При создании таблицы в MSSQL для приема данных из 1С, мы должны предусмотреть колонки, которые позволят нам идентифицировать записи при повторной выгрузке. Если мы просто будем делать INSERT, то при перепроведении документа в 1С во внешней базе возникнут дубли.

Рассмотрим пример структуры таблицы:


CREATE TABLE ExternalAccruals (
    Period DATETIME,
    RecorderGUID UNIQUEIDENTIFIER,
    LineNumber INT,
    CounterpartyGUID UNIQUEIDENTIFIER,
    Amount DECIMAL(15,2),
    PRIMARY KEY (Period, RecorderGUID, LineNumber)
);

Здесь RecorderGUID и LineNumber выступают в роли якоря. При выгрузке мы сначала должны удалить старые записи по данному регистратору, а затем записать новые, либо использовать конструкцию MERGE в SQL.

Использование Менеджера записи для работы через Внешние источники данных

Если вы используете механизм 1С «Внешние источники данных», то система позволяет работать с таблицами SQL почти так же, как с внутренними объектами. Для необъектных данных во внешней базе 1С предоставляет объект МенеджерЗаписи.

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


НоваяЗапись = ВнешниеИсточникиДанных.НашаВнешняяБаза.Таблицы.dbo_ExternalAccruals.СоздатьМенеджерЗаписи();
НоваяЗапись.Period = Движение.Период;
НоваяЗапись.RecorderGUID = Движение.Регистратор.УникальныйИдентификатор();
НоваяЗапись.LineNumber = Движение.НомерСтроки;
НоваяЗапись.Amount = Движение.Сумма;
НоваяЗапись.Записать();

Важный нюанс: Метод Записать() в менеджере записи сначала пытается найти запись по ключевым полям. Если она найдена — обновляет, если нет — создает новую. Это избавляет нас от ручного написания сложных SQL-запросов.

Синхронизация через Планы обмена

Выгружать весь регистр целиком при каждом изменении — плохая практика, особенно если записей миллионы. Проанализируем ситуацию: документ перепровели, движения изменились. Как об этом узнать внешней базе?

Правильным подходом будет использование Планов обмена. Мы можем создать план обмена и включить в состав его состава наш регистр накопления. Рассмотрим шаги реализации:

  1. Создаем план обмена (например, ОбменСВнешнейБазой).
  2. Включаем регистр ВзаиморасчетыСКонтрагентами в состав плана обмена (авторегистрация — «Разрешить»).
  3. При выгрузке выбираем изменения с помощью метода ВыбратьИзменения().
  4. После успешной записи в MSSQL вызываем УдалитьРегистрациюИзменений().

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

Проблема представления ссылочных данных (GUID)

При прямой записи в SQL через ADO или ODBC часто возникает путаница с форматом ГУИДов. В 1С ссылка хранится как Binary(16), а в MSSQL — как Uniqueidentifier. Порядок байтов в 1С отличается от стандартного SQL-представления (байт-сваппинг).

Чтобы избежать проблем при поиске контрагентов или договоров в сторонней базе, мы рекомендуем передавать ГУИД в виде строки или использовать функцию преобразования. Посмотрим на пример получения строкового ГУИДа в 1С:


СтрокаГУИД = Строка(СсылкаНаКонтрагента.УникальныйИдентификатор());
// Результат будет в формате "550e8400-e29b-41d4-a716-446655440000"

На стороне SQL такая строка легко конвертируется в тип UNIQUEIDENTIFIER командой CAST(StringValue AS UNIQUEIDENTIFIER).

Выгрузка итогов вместо детальных записей

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

Рассмотрим вариант выгрузки через Виртуальные таблицы. Вместо физической таблицы регистра мы обращаемся к ОстаткиИОбороты. В этом случае ключом во внешней базе будет набор измерений (Контрагент, Договор, Организация), а ресурсом — СуммаОстаток. Это значительно сокращает объем передаваемых данных и упрощает логику обновления в MSSQL.

Обеспечение транзакционной целостности

При записи во внешний источник данных важно помнить о транзакциях. Если запись в SQL происходит внутри транзакции проведения документа в 1С, то любая ошибка в сети или на стороне SQL-сервера приведет к откату транзакции в 1С. Это хорошо для согласованности данных, но может блокировать работу пользователей при нестабильной связи с внешней базой.

Рассмотрим алгоритм безопасной записи:

  1. Начать транзакцию в 1С.
  2. Выполнить движения по регистру.
  3. Попытаться записать данные во внешний SQL.
  4. Если запись успешна — зафиксировать транзакцию.
  5. Если произошла ошибка — отменить транзакцию 1С и вывести сообщение пользователю.

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

← На главную