Почему при прямом переносе записей регистра через SQL поле регистратора отображается пустым?

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

При переносе больших массивов данных между базами 1С разработчики нередко прибегают к прямой работе с таблицами СУБД через запросы INSERT INTO. Это позволяет избежать длительной выгрузки и загрузки файлов через стандартные механизмы конвертации данных. Однако при таком подходе можно столкнуться со странным поведением платформы: данные в регистр перенесены, записи видны в интерфейсе, но поле Регистратор остается полностью пустым, не выводя даже привычную битую ссылку <Объект не найден>.

Разберем детально, как устроено хранение регистратора на уровне СУБД, выясним причину возникновения пустого значения и проанализируем, как корректно решить эту задачу и избежать критических ошибок при прямой работе с базой данных.

Как 1С хранит ссылки на регистратор в таблицах СУБД

Поле Регистратор в подчиненных регистрах сведений, накопления и бухгалтерии является составным ссылочным типом данных. В базе данных для хранения такого поля платформа выделяет не одну, а две служебные колонки:

  1. _RecorderTRef — бинарный идентификатор типа метаданных (код конкретной таблицы документа-регистратора в текущей конфигурации);
  2. _RecorderRRef — непосредственно уникальный идентификатор (GUID) конкретного документа в формате binary(16).

Поведение платформы при отображении регистратора зависит от корректности каждого из этих полей:

  1. Если код типа метаданных в _RecorderTRef указан верно (соответствует объекту, входящему в список допустимых регистраторов данного регистра), но ссылка в _RecorderRRef не существует в соответствующей таблице документа, 1С выводит строку <Объект не найден...>.
  2. Если значение поля _RecorderTRef не существует в текущей структуре метаданных базы-приемника или не входит в перечень разрешенных типов регистраторов для этой таблицы, платформа не может инициализировать составной тип данных. В результате значение расценивается как некорректный тип и интерпретируется как пустое значение (Неопределено).

Причина несовпадения кодов типов метаданных

Коды типов метаданных (TRef) генерируются платформой динамически при создании и реструктуризации объектов. Если база-источник и база-приемник отличаются версиями конфигурации (например, УТ 10.3.19 и УТ 10.3.40) либо в одной из них выполнялись доработки структуры, идентификаторы таблиц в СУБД для одного и того же типа документа неизбежно разойдутся.

Например, для документа «Корректировка записей регистров» код типа в базе-источнике может иметь значение 0x000000AE, а в обновленной базе-приемнике — 0x000000C3. Простое копирование исходного значения приводит к тому, что СУБД возвращает неизвестный для новой конфигурации код, и поле регистратора отображается пустым.

Пошаговое исправление значения _RecorderTRef в базе-приемнике

Для исправления ситуации выполним следующие шаги:

  1. Создадим вручную в базе-приемнике один тестовый документ нужного типа (в нашем примере — «Корректировка записей регистров») и запишем с его помощью одну тестовую строку в целевой регистр сведений.
  2. Выполним SQL-запрос к таблице регистра сведений в базе-приемнике и определим правильное локальное значение поля _RecorderTRef:
    
    SELECT TOP 1 _RecorderTRef, _RecorderRRef 
    FROM dbo._InfoRg8560 
    WHERE _RecorderRRef = 0x...; -- GUID созданного тестового документа
    
  3. Выполним обновление записей регистра, заменив скопированный код типа регистратора на актуальный локальный код:
    
    UPDATE dbo._InfoRg8560
    SET _RecorderTRef = 0x000000C3
    WHERE _RecorderTRef = 0x000000AE;
    
  4. После выполнения инструкции обновим динамический список в интерфейсе 1С — регистраторы начнут корректно отображаться штатными ссылками на документы.

Особенности преобразования GUID 1C в binary(16) для СУБД

Если при манипуляциях с базой данных требуется вручную сопоставлять ссылки документов, необходимо помнить об особенностях хранения уникальных идентификаторов в 1С. Платформа использует специфический порядок байтов (byte swap) при переводе строкового GUID в бинарное поле binary(16).

Рассмотрим структуру строкового GUID вида: AAAAAAAA-BBBB-CCCC-DDDD-EEEEEEEEEEEE. При сохранении в поле СУБД байты переставляются следующим образом:

  1. Первые 8 байт формируются из второй части идентификатора: блок DDDD и блок EEEEEEEEEEEE без изменений порядка байтов.
  2. Следующие 8 байт формируются из блоков первой части, причем каждый блок переворачивается побайтово: сначала блок CCCC с реверсом, затем блок BBBB с реверсом, и в конце блок AAAAAAAA с реверсом.

Прямое преобразование через функции СУБД без учета реверса байтов приведет к поиску несуществующей ссылки.

Скрытые риски и проблемы прямого INSERT в базу 1С

Прямая вставка записей в таблицы СУБД в обход сервера приложений 1С влечет за собой серьезные риски нарушить целостность данных:

  1. Кэш сервера приложений: Кластер серверов 1С кэширует считанные структуры и таблицы. Данные, добавленные напрямую через SQL, не инвалидируют кэш. Пользователи и серверные методы могут не видеть новые строки до перезапуска рабочих процессов службы кластера.
  2. Поле _LineNo и кластерный индекс: В подчиненных регистрах кластерный индекс формируется по колонкам _RecorderTRef, _RecorderRRef и _LineNo (номер строки). Нумерация строк для каждого регистратора обязана начинаться строго с 1 и идти последовательно без пропусков и дублирования. При нарушении нумерации штатное чтение набора записей завершится ошибкой.
  3. Очистка движений: Если в дальнейшем перенесенный документ попытаются отменить, пометить на удаление или перепровести, платформа попытается перечитать и очистить движения через менеджер набора записей. Ошибки в служебных полях заблокируют эти операции.
  4. Таблицы итогов для регистров накопления и бухгалтерии: При переносе остатков по регистрам накопления прямой INSERT наполняет только таблицу движений. Таблицы итогов (остатков и оборотов) не обновляются. Виртуальные таблицы отчетов и запросов будут возвращать пустые или неверные данные до принудительного пересчета итогов в режиме «Тестирование и исправление» или обработке «Управление итогами».
  5. Планы обмена: Вставка через СУБД не регистрирует изменения в служебных таблицах _ChngR*. Данные не уйдут в узлы РИБ и внешние интеграции без ручного вызова метода ПланыОбмена.ЗарегистрироватьИзменения().

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

Чтобы исключить риски повреждения служебных структур СУБД, для массовой загрузки данных рекомендуется использовать оптимизированные штатные механизмы платформы:

  1. Запись набора с отключением бизнес-логики: Использование объекта РегистрСведенийНаборЗаписей с установкой свойства загрузки данных перед сохранением:
    
    Набор = РегистрыСведений.ЦеныАТТ.СоздатьНаборЗаписей();
    Набор.Отбор.Регистратор.Установить(ДокументСсылка);
    Набор.ОбменДанными.Загрузка = Истина;
    // Заполнение набора записей
    Набор.Записать();
    
    Режим ОбменДанными.Загрузка = Истина отключает выполнение подписок на события, проверку прав и обработчики проведения, что приближает скорость записи к прямому обращению к СУБД.
  2. Временное отключение итогов: Для регистров накопления перед массовой загрузкой программно отключается расчет итогов через метод РегистрыНакопления[ИмяРегистра].УстановитьИспользованиеИтогов(Ложь). После завершения всей загрузки итоги включаются обратно с однократным пересчетом.
  3. Многопоточная запись: Разбиение массива регистраторов на пакеты и запись наборов параллельно через несколько потоков с помощью вызова ФоновыеЗадания.Выполнить().
  4. Комбинированный подход: Чтение данных напрямую из базы-источника через ADO/ODBC или «Внешние источники данных» (что исключает формирование тяжелых промежуточных XML-файлов) с последующей порционной записью в базу-приемник стандартными наборами записей 1С.
← На главную