В процессе интеграции информационных систем, настройки распределенных баз данных (РИБ) или восстановления синхронизации после сбоев обмена разработчики часто сталкиваются с необходимостью сопоставить или изменить уникальные идентификаторы (GUID/UUID) существующих элементов справочников или документов. Напрямую отредактировать поле УникальныйИдентификатор у уже записанного в базу объекта стандартными средствами платформы невозможно. Это ограничение заложено в архитектуру платформы для обеспечения ссылочной целостности базы данных.
В рамках этой статьи мы подробно разберем, как решить задачу изменения GUID в 1С:Предприятии безопасными методами, проанализируем изящные обходные пути вроде XML-сериализации, изучим архитектурные альтернативы через регистры соответствия обмена, а также детально разберем, почему прямое вмешательство в таблицы СУБД (SQL Update) несет в себе колоссальные риски для стабильности системы.
Рассмотрим по шагам все доступные инструменты и выработаем оптимальную стратегию работы.
Если нам необходимо физически изменить GUID существующего объекта в базе данных, единственным штатным программным решением является создание нового элемента-копии с целевым идентификатором и последующая замена всех ссылок на него по всей базе данных с последующим удалением старого элемента.
Разберем этот алгоритм на примере справочника Номенклатура:
УстановитьСсылкуНового().Посмотрим на практическую реализацию этого метода на встроенном языке 1С:
// Предположим, у нас есть старый объект, ссылку на который нужно переопределить
СтарыйОбъектСсылка = Справочники.Номенклатура.НайтиПоКоду("00001");
// Проверяем, найден ли исходный элемент
Если ЗначениеЗаполнено(СтарыйОбъектСсылка) Тогда
// Задаем новый GUID, который мы хотим присвоить элементу
СтрокаНовогоGUID = "12345678-1234-1234-1234-123456789abc";
НовыйGUID = Новый УникальныйИдентификатор(СтрокаНовогоGUID);
// Формируем будущую ссылку для нового элемента
НоваяСсылка = Справочники.Номенклатура.ПолучитьСсылка(НовыйGUID);
// Создаем новый объект копированием реквизитов старого
НовыйОбъект = Справочники.Номенклатура.СоздатьЭлемент();
ЗаполнитьЗначенияСвойств(НовыйОбъект, СтарыйОбъектСсылка.ПолучитьОбъект(), "Код, Наименование");
// Важно: переносим также и другие реквизиты, если это необходимо
// Устанавливаем подготовленную ссылку для еще НЕ записанного объекта
НовыйОбъект.УстановитьСсылкуНового(НоваяСсылка);
Попытка
НовыйОбъект.Записать();
Сообщить("Новый элемент успешно записан с GUID: " + Строка(НовыйОбъект.Ссылка.УникальныйИдентификатор()));
Исключение
ВызватьИсключение "Не удалось записать новый объект: " + ОписаниеОшибки();
КонецПопытки;
КонецЕсли;
Важное ограничение метода: Функция УстановитьСсылкуНового() работает исключительно для новых, еще ни разу не записанных в базу объектов (у которых свойство ЭтоНовый() возвращает значение Истина). Попытка применить этот метод к уже сохраненному в базе элементу вызовет критическую ошибку платформы.
После создания нового элемента со скопированными реквизитами нам потребуется выполнить замену ссылок. Для этого рекомендуется использовать типовую обработку "Поиск и замена значений" или программно вызвать методы платформы, такие как НайтиСсылки() и произвести замену во всех найденных объектах-метаданных с последующей перезаписью.
Ручной перенос реквизитов (особенно у сложных справочников со множеством табличных частей или у документов) — процесс трудоемкий и чреватый ошибками. Мы можем упустить скрытые реквизиты, свойства или дополнительные сведения.
Для создания абсолютно точной копии объекта с новым GUID эффективнее всего использовать механизм XML-сериализации. Суть метода заключается в том, что мы выгружаем объект в текстовый XML-формат, программно заменяем в полученном тексте старый GUID на новый и десериализуем объект обратно. Платформа мгновенно воссоздает полную структуру данных, включая все табличные части.
Проанализируем программный код, реализующий данный подход:
Функция КлонироватьОбъектСНовымGUID(СтарыйОбъектСсылка, СтрокаНовогоGUID) Экспорт
СтарыйОбъект = СтарыйОбъектСсылка.ПолучитьОбъект();
// Сериализуем исходный объект в строку XML
ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.УстановитьСтроку();
ЗаписатьXML(ЗаписьXML, СтарыйОбъект);
XMLТекст = ЗаписьXML.Закрыть();
// Получаем строковое представление старого GUID
СтрокаСтарогоGUID = Строка(СтарыйОбъектСсылка.УникальныйИдентификатор());
// Производим замену старого идентификатора на новый в тексте XML
МодифицированныйXMLТекст = СтрЗаменить(XMLТекст, СтрокаСтарогоGUID, СтрокаНовогоGUID);
// Десериализуем объект из измененной строки XML
ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.УстановитьСтроку(МодифицированныйXMLТекст);
НовыйОбъект = ПрочитатьXML(ЧтениеXML);
// Принудительно устанавливаем ссылку, так как при чтении XML
// объект может инициализироваться как существующий в памяти
НовыйGUID = Новый УникальныйИдентификатор(СтрокаНовогоGUID);
НоваяСсылка = Справочники[СтарыйОбъектСсылка.Метаданные().Имя].ПолучитьСсылка(НовыйGUID);
НовыйОбъект.УстановитьСсылкуНового(НоваяСсылка);
Возврат НовыйОбъект;
КонецФункции
Использование XML-сериализации значительно снижает риски потери связанных данных внутри объекта при его дублировании и существенно ускоряет разработку универсальных обработок по изменению GUID.
В большинстве случаев необходимость изменения GUID возникает из-за рассинхронизации баз при обмене данными. Вместо того чтобы подвергать базу данных рискам массовой замены ссылок (что может привести к перезаписи документов, пересчету итогов и деградации производительности), правильнее использовать стандартные архитектурные решения платформы 1С.
В конфигурациях, построенных на базе Библиотеки стандартных подсистем (БСП), для этих целей существует специальный Регистр сведений "Соответствие объектов информационных баз". Этот регистр хранит связи между уникальными идентификаторами объектов в разных информационных базах.
Вместо физического изменения GUID в базе-приемнике мы можем просто сделать запись в этот регистр:
При последующих обменах данными (через универсальный формат обмена EnterpriseData или правила конвертации) механизмы БСП будут автоматически сопоставлять эти объекты "на лету", не создавая дублей и избавляя разработчика от необходимости менять системные идентификаторы в транзакционных таблицах.
Иногда у администраторов баз данных возникает соблазн выполнить низкоуровневый запрос к СУБД (например, в MS SQL Server или PostgreSQL), обновив поля идентификаторов напрямую в таблицах. Рассмотрим причины, по которым делать это категорически запрещено на работающих продакшн-базах:
binary(16) (например, поле _IDRRef для ссылок на объекты или поля реквизитов _Fld...RRef). При этом порядок записи байт в СУБД "перевернут" по особому внутреннему алгоритму 1С по сравнению со строковым представлением UUID в режиме "1С:Предприятие".
Обычная запись строки GUID в SQL-поле приведет к физическому повреждению ссылки. Для корректного прямого изменения требуется применять сложные функции побайтового преобразования, что усложняет процесс и увеличивает вероятность ошибки.
rphost) кэширует структуру данных и идентификаторы часто используемых объектов в оперативной памяти. Если изменить GUID непосредственно в SQL-таблице в обход сервера приложений, сервер 1С об этом изменении не узнает. При обращении пользователей к измененному объекту возникнут непредсказуемые сбои блокировок, рассогласование транзакций и критические ошибки "Объект не найден". Потребуется как минимум очистка кэша сервера и перезапуск службы 1С.
_IDRRef) способно разрушить логические связи между таблицами. В результате "поедут" итоги регистров накопления и сведений, нарушится структура подчиненных документов, и база данных может полностью потерять внутреннюю консистентность.
Если ваша информационная система функционирует в режиме Распределенной Информационной Базы (РИБ), физическая замена элементов и их GUID требует предельной осторожности.
Создание нового дублирующего элемента и удаление старого неизбежно порождает регистрацию изменений на узлах планов обмена. Эти изменения начнут мигрировать по периферийным базам данных. Если в этот момент в одном из филиалов велась активная работа со старым объектом (например, создавались новые документы с его участием), то при синхронизации возникнет жесткий конфликт автосинхронизации. Это гарантированно приведет к лавинообразному появлению дублей по всей сети или к массовому возникновению битых ссылок вида "Объект не найден", устранять которые в ручном режиме в сотни раз сложнее.
Подводя итоги нашего анализа, выделим ключевые правила интерактивного и программного изменения GUID в 1С:
_IDRRef.УстановитьСсылкуНового() отрабатывает только до первой записи объекта в базу.