Смена уникального идентификатора объекта в 1С 8.3: пересоздание, COM и битые ссылки

· 9 мин

Содержание

Изменить GUID у уже записанного объекта в 1С нельзя: уникальный идентификатор — это и есть ссылка, платформа не даёт её переписать. «Сменить GUID» на практике означает другое: создать копию объекта с нужным идентификатором через УстановитьСсылкуНового(), перевести на неё все ссылки в базе и удалить старый объект.

Частое заблуждение — что GUID хранится в каком-то реквизите и его можно поправить обработкой «Групповое изменение реквизитов». Такого реквизита нет. Ниже — рабочие способы для 1С:Предприятия 8.3: код во внешней обработке, COM-соединение, массовая замена при миграции и восстановление битых ссылок. Всё это общий механизм платформы, он одинаков в БП 3.0, ЗУП 3.1, УТ 11 и других конфигурациях.

Зачем меняют идентификатор и когда этого делать не стоит

GUID объекта используется везде, где базы обмениваются данными. По нему узел обмена понимает, что «Ромашка ООО» в бухгалтерии и в торговле — один и тот же контрагент.

Типичные сценарии, когда идентификатор приходится менять:

  • 🔁 Дубли после синхронизации. Один и тот же товар завели вручную в двух базах. GUID разные, обмен создаёт второй элемент.
  • 📦 Миграция данных. Справочники переносят в новую базу, а внешняя система (сайт, WMS, CRM) хранит старые GUID и должна продолжать их узнавать.
  • 🧩 Восстановление битых ссылок. В документах висит <Объект не найден>, а нужный элемент удалили. Его пересоздают с тем же идентификатором — и ссылки «оживают».
  • 🔗 Интеграции по API. Внешний сервис заранее выдал свой UUID, и объект в 1С должен получить именно его.

Когда делать не нужно:

  • ❌ Если дубли видны только в одной базе — проще объединить элементы стандартной обработкой поиска дублей, чем возиться с идентификаторами.
  • ❌ Если обмен идёт через подсистему БСП, соответствие объектов можно задать в настройках синхронизации без смены GUID: подсистема хранит пары «наш объект — объект другой базы».
  • ❌ Для записей регистров сведений и значений перечислений. У записей регистров ссылки нет вообще, а GUID значений перечислений задаются в конфигурации и в данных не меняются.
Перед сменой GUID
Выполнено: 0 / 5

Пересоздание объекта с нужным GUID программно

Основной инструмент — метод УстановитьСсылкуНового(). Он есть у объектов справочников, документов, планов видов характеристик, планов счетов, планов видов расчёта, бизнес-процессов, задач и планов обмена. Вызывать его можно только у нового, ещё не записанного объекта.

Порядок действий:

  1. Получить ссылку с нужным GUID через менеджер: Справочники.Номенклатура.ПолучитьСсылку(Ид).
  2. Убедиться, что объекта с таким идентификатором в базе ещё нет.
  3. Скопировать старый объект методом Скопировать() — табличные части скопируются вместе с ним.
  4. Назначить копии новую ссылку и записать.
  5. Заменить старую ссылку на новую во всех данных.
  6. Пометить старый объект на удаление и удалить.

Код для серверного модуля внешней обработки (пример для справочника «Номенклатура»):

&НаСервереБезКонтекста
Функция ПересоздатьСНовымGUID(СтараяСсылка, СтрокаGUID)

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

    Если НоваяСсылка.ПолучитьОбъект() <> Неопределено Тогда
        ВызватьИсключение "В базе уже есть объект с GUID " + СтрокаGUID;
    КонецЕсли;

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

    Возврат НоваяСсылка;

КонецФункции

ОбменДанными.Загрузка = Истина отключает обработчики ПередЗаписью и ПриЗаписи конфигурации. Иначе типовая проверка может отказать в записи из-за «дубля» по наименованию или ИНН.

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

Документы

Для документа схема та же: Документы.РеализацияТоваровУслуг.ПолучитьСсылку(Ид), затем Скопировать() и УстановитьСсылкуНового(). Разница — в движениях. Копия записывается без проведения, поэтому:

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

Замена ссылок на старый объект

В конфигурациях на БСП (все актуальные типовые) замену делает функция ОбщегоНазначения.ЗаменитьСсылки(). Она проходит по всем таблицам и возвращает таблицу ошибок:

ПарыЗамен = Новый Соответствие;
ПарыЗамен.Вставить(СтараяСсылка, НоваяСсылка);
Ошибки = ОбщегоНазначения.ЗаменитьСсылки(ПарыЗамен);

Без БСП остаётся НайтиПоСсылкам(): он возвращает таблицу с колонками Ссылка, Данные, Метаданные. Каждую найденную запись придётся перезаписать своим кодом — это долго, но надёжно для одной-двух таблиц.

Смена UUID через COM-соединение

COM-соединение нужно, когда GUID берут из одной базы и проставляют в другую: например, при выравнивании справочников между бухгалтерией и торговлей. Подключение работает только на Windows и только при зарегистрированной библиотеке comcntr.dll той же разрядности, что и вызывающая программа.

Если V83.COMConnector не создаётся, зарегистрируйте компоненту из командной строки от имени администратора:

regsvr32 "C:\Program Files\1cv8\8.3.24.1548\bin\comcntr.dll"

Номер версии в пути подставьте свой — по каталогу установленной платформы.

Подключение из 1С к файловой и серверной базе:

Коннектор = Новый COMОбъект("V83.COMConnector");

// файловая база
База = Коннектор.Connect("File=""D:\Bases\Trade"";Usr=""Администратор"";Pwd=""""");

// серверная база
// База = Коннектор.Connect("Srvr=""srv1c"";Ref=""trade"";Usr=""Администратор"";Pwd=""""");

Ид     = База.NewObject("УникальныйИдентификатор", СтрокаGUID);
Ссылка = База.Справочники.Номенклатура.ПолучитьСсылку(Ид);

Через COM можно выполнить всю схему из предыдущего раздела, но каждое обращение к свойствам удалённого объекта — это межпроцессный вызов. На тысячах элементов это медленно.

💡 Быстрее положить функцию ПересоздатьСНовымGUID в общий модуль целевой базы с флагами «Сервер» и «Внешнее соединение», сделать её экспортной и вызывать одной строкой: База.МойМодуль.ПересоздатьСНовымGUID(...). Тогда работа идёт внутри базы, а через COM летит только строка GUID.

Строку идентификатора из базы-источника получают так: Строка(Ссылка.УникальныйИдентификатор()).

Идентификаторы объектов метаданных в Конфигураторе

У объектов конфигурации — справочников, реквизитов, табличных частей — тоже есть свои GUID. Платформа по ним сопоставляет метаданные с таблицами базы данных. Пользователь их не видит, увидеть можно в XML: Конфигурация → Выгрузить конфигурацию в файлы, атрибут uuid у каждого объекта.

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

Ситуации, где это всплывает:

СитуацияЧто происходитКак быть
Реквизит удалили и создали заново с тем же именемНовый uuid, старые значения потеряныВернуть реквизит из резервной копии конфигурации или из хранилища
Две конфигурации развивались отдельноОдинаковые объекты имеют разные uuidПри сравнении и объединении сопоставлять объекты по именам
Расширение заимствует объект основной конфигурацииРасширение ссылается на объект по uuidЕсли объект в основной пересоздали, заимствование нужно сделать заново

При сравнении и объединении конфигураций, которые не связаны отношением поддержки, Конфигуратор предлагает сопоставить объекты по именам. Используйте этот режим вместо ручной правки uuid в XML.

Массовая смена GUID при миграции и синхронизации

Когда идентификаторов сотни и тысячи, вызывать функцию по одному объекту неудобно. Есть два рабочих подхода.

Таблица соответствий

Подготовьте файл с парами «старый GUID — новый GUID» или «код — новый GUID». Обработка читает файл, для каждой строки пересоздаёт объект и копит пары в одном Соответствии. Замену ссылок делайте одним вызовом ЗаменитьСсылки() на весь пакет: так база сканируется один раз, а не тысячу.

Перенос через XML с сохранением GUID

Сериализация ЗаписатьXML() / ПрочитатьXML() пишет в файл и ссылку объекта. При загрузке объект создаётся с тем же GUID. На этом построена универсальная обработка выгрузки и загрузки данных в XML: перенесённые справочники сохраняют идентификаторы. Если GUID нужен новый, его подменяют в XML-файле до загрузки — замена строки в тексте файла меняет и ссылку, и все упоминания объекта в выгружаемых документах.

Загрузку в базу, где объекты уже есть, проверяйте на копии. Объект с совпавшим GUID перезапишется данными из файла.

Порядок для миграции:

  1. Приостановите обмены, чтобы узлы не получили промежуточные изменения.
  2. Выполните смену GUID в базе-приёмнике.
  3. Удалите старые объекты через Администрирование → Обслуживание → Корректировка данных → Удаление помеченных объектов (путь для БП 3.0; в других типовых он в том же разделе администрирования).
  4. В обменах БСП очистите сопоставление для перенесённых объектов, иначе узел помнит связь со старой ссылкой.
  5. Запустите синхронизацию и проверьте, что новых дублей не появилось.

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

Как проверить, что старый GUID больше нигде не используется

Удаление помеченных объектов само откажется удалять элемент, на который ещё есть ссылки. Но лучше проверить заранее, чтобы не разбираться с отказами на сотнях объектов.

Проверка одной ссылкой:

Массив = Новый Массив;
Массив.Добавить(СтараяСсылка);
Найденные = НайтиПоСсылкам(Массив);

Для Каждого СтрокаТаблицы Из Найденные Цикл
    Сообщить(СтрокаТаблицы.Метаданные.ПолноеИмя() + ": " + Строка(СтрокаТаблицы.Данные));
КонецЦикла;

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

На что смотреть отдельно:

  • 🌳 Иерархия. У подчинённых элементов реквизит Родитель указывает на старую группу. Функция замены ссылок переставляет и его, но после ручной замены через НайтиПоСсылкам() подчинённые легко забыть.
  • 📊 Регистры с запретом редактирования. Движения документов меняются вместе с перепроведением. Если документ закрыт датой запрета изменения, замена в его движениях может не пройти — временно сдвиньте дату запрета и верните её после.
  • 🔐 Сохранённые настройки. Отборы в отчётах и пользовательские настройки списков хранят ссылку на объект. После удаления в таких отборах появится битая ссылка — пользователю придётся выбрать элемент заново.
  • 🌐 Внешние системы. Сайт или WMS, которые хранят старый GUID, о замене не узнают. Передайте им таблицу соответствий до того, как удалите старые объекты.

Как вернуть битые ссылки «Объект не найден»

Если элемент справочника удалили напрямую, без контроля ссылок, документы показывают вместо него строку вида <Объект не найден> (36:80c40050569f2e9f11e73b13d8aeb2a6). Число до двоеточия — внутренний номер таблицы, после — GUID удалённого объекта.

Восстановить ссылку просто: создать объект ровно с этим GUID. Сама «битая» ссылка идентификатор помнит, поэтому строку разбирать не обязательно:

БитаяСсылка = Документ.Контрагент;
Ид = БитаяСсылка.УникальныйИдентификатор();

Если БитаяСсылка.ПолучитьОбъект() = Неопределено Тогда
    Объект = Справочники.Контрагенты.СоздатьЭлемент();
    Объект.УстановитьСсылкуНового(Справочники.Контрагенты.ПолучитьСсылку(Ид));
    Объект.Наименование = "Восстановленный " + Строка(Ид);
    Объект.ОбменДанными.Загрузка = Истина;
    Объект.Записать();
КонецЕсли;

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

Если на руках только текст сообщения, учтите: 32 символа после двоеточия идут не в порядке строки GUID. Группы переставлены: сначала четвёртая и пятая, затем третья, вторая и первая. Функция сборки:

Функция GUIDИзБитойСсылки(Хвост)
    // Хвост — 32 символа после двоеточия
    Возврат Сред(Хвост, 25, 8) + "-" + Сред(Хвост, 21, 4) + "-"
        + Сред(Хвост, 17, 4) + "-" + Сред(Хвост, 1, 4) + "-" + Сред(Хвост, 5, 12);
КонецФункции

Для примера выше получится d8aeb2a6-3b13-11e7-80c4-0050569f2e9f.

💡 Номер таблицы из сообщения подскажет, какой справочник удалён, но опираться на него между базами нельзя: он внутренний и может отличаться. Тип объекта надёжнее смотреть по типу реквизита в конфигурации.

Частые вопросы

Меняется ли GUID при выгрузке и загрузке базы в .dt?
Нет. Файл .dt переносит базу целиком, все ссылки и идентификаторы сохраняются.
Получает ли копия элемента, созданная кнопкой «Скопировать», тот же GUID?
Нет, у копии всегда новый идентификатор. Свой GUID задаётся только программно через УстановитьСсылкуНового().
Могут ли в двух разных базах быть объекты с одинаковым GUID?
Да, и это нормально: так выглядят объекты, пришедшие через обмен или перенос XML. Внутри одной базы и одной таблицы совпадение невозможно.
Можно ли сгенерировать GUID заранее, до записи объекта?
Да: Новый УникальныйИдентификатор() без параметров даёт случайный идентификатор. Его можно сохранить во внешней системе, а потом создать объект с этой ссылкой.
Почему после смены GUID обмен снова создал дубль?
Скорее всего, в узле обмена осталось старое сопоставление объектов. Очистите его для этих объектов и повторите синхронизацию.