Как изменить GUID у существующего документа в 1С?

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

При обмене данными между несколькими информационными базами или внешними сервисами иногда возникает критическая ситуация: уникальный идентификатор (GUID / UUID) нового документа совпадает с идентификатором ранее созданного или уже выгруженного объекта. Разберем, почему в платформе 1С нельзя просто отредактировать свойство Ссылка у существующего объекта, какими способами можно безопасно сменить идентификатор и как предотвратить подобные коллизии в будущем.

Почему нельзя просто переписать GUID у существующего объекта

Проанализируем архитектурные ограничения платформы 1С:Предприятие:

  1. Неизменяемость ссылки: У любого записанного в базу объекта (когда ЭтоНовый() = Ложь) свойство Ссылка доступно строго только для чтения.
  2. Метод назначения ссылки: Функция УстановитьСсылкуНового() работает исключительно до первого сохранения объекта в информационную базу.
  3. Кэширование на сервере 1С: Рабочие процессы кластера серверов кэшируют ссылки на объекты в оперативной памяти. Любое нештатное изменение идентификатора в обход объектной модели платформы приводит к рассинхронизации кэша и фантомным ошибкам чтения.
  4. Уникальные индексы в СУБД: В таблице документа поле _IDRRef (соответствующее ссылке) входит в уникальный кластерный индекс, а также выступает внешним ключом для всех подчиненных табличных частей и движений по регистрам.

Способ 1. Программное пересоздание документа и замена ссылок (Рекомендуемый)

Рассмотрим основной и самый надежный способ смены идентификатора средствами платформы 1С. Идея заключается в создании точной копии документа с новым GUID, копировании его движений, замене ссылок по всей базе данных и последующем удалении исходного документа.

Разберем пошаговый алгоритм выполнения этой операции:

  1. Создаем новый уникальный идентификатор и инициализируем новую ссылку через менеджер документа.
  2. Создаем новый документ и назначаем ему сгенерированную ссылку через УстановитьСсылкуНового().
  3. Копируем реквизиты шапки и табличные части из старого документа в новый.
  4. Записываем новый документ в режиме ОбменДанными.Загрузка = Истина, чтобы избежать повторного выполнения логики проведения и проверок заполнения.
  5. Переносим движения по всем регистрам со старого документа-регистратора на новый.
  6. Выполняем поиск и замену старой ссылки на новую во всех связанных объектах базы данных.
  7. Удаляем исходный документ с включенным режимом загрузки.

Посмотрим на пример программной реализации такого переноса:


// Получаем исходный документ для замены
СтарыйДокументОбъект = СтараяСсылка.ПолучитьОбъект();

// Генерируем новый GUID и получаем ссылку
НовыйГУИД = Новый УникальныйИдентификатор();
НоваяСсылка = Документы[СтараяСсылка.Метаданные().Имя].ПолучитьСсылку(НовыйГУИД);

// Создаем документ-клон и устанавливаем ему новую ссылку
НовыйДокументОбъект = Документы[СтараяСсылка.Метаданные().Имя].СоздатьДокумент();
НовыйДокументОбъект.УстановитьСсылкуНового(НоваяСсылка);

// Заполняем реквизиты и табличные части
НовыйДокументОбъект.Заполнить(СтарыйДокументОбъект);
НовыйДокументОбъект.Дата = СтарыйДокументОбъект.Дата;
НовыйДокументОбъект.Номер = СтарыйДокументОбъект.Номер;
НовыйДокументОбъект.Проведен = СтарыйДокументОбъект.Проведен;
НовыйДокументОбъект.ПометкаУдаления = СтарыйДокументОбъект.ПометкаУдаления;

Для Каждого ТЧ Из СтарыйДокументОбъект.Метаданные().ТабличныеЧасти Цикл
    НовыйДокументОбъект[ТЧ.Имя].Загрузить(СтарыйДокументОбъект[ТЧ.Имя].Выгрузить());
КонецЦикла;

// Записываем новый документ без проверок
НовыйДокументОбъект.ОбменДанными.Загрузка = Истина;
НовыйДокументОбъект.Записать(?(НовыйДокументОбъект.Проведен, РежимЗаписиДокумента.Проведение, РежимЗаписиДокумента.Запись));

// Переносим движения по всем регистрам
Для Каждого Движение Из СтарыйДокументОбъект.Движения Цикл
    Движение.Прочитать();
    Если Движение.Количество() > 0 Тогда
        НаборНового = НовыйДокументОбъект.Движения[Движение.Метаданные().Имя];
        НаборНового.Очистить();
        Для Каждого Запись Из Движение Цикл
            ЗаполнитьЗначенияСвойств(НаборНового.Добавить(), Запись);
        КонецЦикла;
        НаборНового.ОбменДанными.Загрузка = Истина;
        НаборНового.Записать();
    КонецЕсли;
КонецЦикла;

// Выполняем замену ссылок в базе данных
МассивСтарых = Новый Массив;
МассивСтарых.Добавить(СтараяСсылка);

ТаблицаПоиска = НайтиПоСсылкам(МассивСтарых);
Для Каждого Стр Из ТаблицаПоиска Цикл
    ОбъектДляЗамены = Стр.Данные.ПолучитьОбъект();
    Если ОбъектДляЗамены <> Неопределено И ОбъектДляЗамены.Ссылка <> НоваяСсылка Тогда
        ОбъектДляЗамены.ОбменДанными.Загрузка = Истина;
        // Заменяем значение ссылки в реквизите или строке ТЧ
        // и перезаписываем зависимый объект
        ОбъектДляЗамены.Записать();
    КонецЕсли;
КонецЦикла;

// Удаляем старый документ
СтарыйДокументОбъект.ОбменДанными.Загрузка = Истина;
СтарыйДокументОбъект.Удалить();

Для интерактивной замены ссылок также можно воспользоваться стандартными инструментами, такими как типовая обработка «Поиск и замена значений» или функционал подсистемы управления ссылками в специализированных консолях разработчика.

Способ 2. Изменение GUID на уровне СУБД (SQL) и сопутствующие риски

Прямое обновление поля _IDRRef в таблицах Microsoft SQL Server или PostgreSQL технически возможно, но сопряжено с максимальным уровнем риска для целостности базы данных. Разберем, с какими сложностями придется столкнуться:

  1. Формат хранения идентификаторов: Платформа 1С сохраняет GUID в типе binary(16) со специфической перестановкой байтов (Endianness). Простое преобразование стандартной строки UUID в бинарный вид не совпадет с форматом 1С, что приведет к повреждению ссылочной целостности.
  2. Множество связанных таблиц: Для полного изменения одного документа необходимо обновить значение _IDRRef / _DocumentX_IDRRef не только в таблице _DocumentX, но и во всех подчиненных табличных частях _DocumentX_VT..., во всех таблицах регистров накопления, бухгалтерии, сведений и расчета, где данный документ выступает регистратором или реквизитом.
  3. Таблицы регистрации изменений: Если база включена в распределенную информационную базу (РИБ) или настроен план обмена, потребуется обновить таблицы изменений _NodeX_....
  4. Очистка кэша: После выполнения SQL-скриптов обязателен перезапуск службы кластера серверов 1С (ragent) и полное выполнение процедуры «Тестирование и исправление» с пересчетом итогов.

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

Способ 3. Предотвращение коллизий на уровне интеграции

Выясним причину, почему вообще происходит дублирование GUID. Как правило, коллизии возникают в базах-клонах (развернутых из одной резервной копии), при выгрузке/загрузке через XML без очистки ссылок либо при детерминированном вычислении GUID по простым алгоритмам. Если внутренний GUID документа в базе менять нежелательно, правильнее изменить подход к формированию идентификатора для внешних систем.

Рассмотрим альтернативные архитектурные решения:

  1. Использование регистра соответствий: Создаем непериодический независимый регистр сведений (например, СоответствиеВнешнихИдентификаторов) с измерениями Объект (тип ДокументСсылка) и ресурсом ВнешнийИдентификатор (тип Строка или УникальныйИдентификатор). При первичной выгрузке генерируем новый уникальный GUID, записываем связку в регистр и в дальнейшем берем идентификатор только из него.
  2. Формирование составного ключа: Если внешняя система принимает строковые идентификаторы, передаем составной ключ вида ПрефиксБазы + "_" + GUID, что гарантирует уникальность в разрезе источников данных.
← На главную