Реквизит с GUID в справочнике и документе 1С: от Конфигуратора до обмена

· 9 мин

Содержание

Чтобы добавить идентификатор в 1С, откройте объект в Конфигураторе, на вкладке «Данные» создайте реквизит с типом УникальныйИдентификатор, включите индексирование и заполняйте его в модуле объекта через Новый УникальныйИдентификатор. Затем обновите конфигурацию базы данных и одной обработкой заполните уже существующие элементы.

Такой реквизит нужен, когда у справочника или документа должен быть свой стабильный ключ для обмена с сайтом, CRM, складской системой или другой базой 1С. Ниже — порядок работ для платформы 8.3: от структуры метаданных до поиска объекта по GUID, который пришёл извне.

Сначала решите: нужен ли отдельный реквизит

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

СитуацияЧто использоватьПочему
Внешняя система принимает ключи от 1СGUID ссылкиОн уже есть у каждого объекта, ничего добавлять не надо
Объекты создаются в 1С из внешней системы, и её ключ надо сохранитьУстановитьСсылкуНового() или отдельный реквизитСсылка 1С совпадёт с внешним ключом либо ключ хранится рядом
У одного объекта несколько внешних систем со своими ключамиОтдельный реквизит на каждую систему или регистр сведенийОдна ссылка не может хранить два разных GUID
Внешний ключ не в формате GUID (число, артикул, строка)Реквизит типа Строка или ЧислоТип УникальныйИдентификатор примет только строку формата GUID

💡 Приём, о котором часто забывают: при создании объекта по данным извне ему можно сразу задать ссылку с нужным GUID.

УИД = Новый УникальныйИдентификатор(ВходящийGUIDСтрокой);
НовыйЭлемент = Справочники.Контрагенты.СоздатьЭлемент();
НовыйЭлемент.УстановитьСсылкуНового(Справочники.Контрагенты.ПолучитьСсылку(УИД));
НовыйЭлемент.Наименование = ВходящееНаименование;
НовыйЭлемент.Записать();

После этого внешний ключ и ссылка 1С — одно и то же значение. Ищут такой объект через ПолучитьСсылку(), без отдельного реквизита и без запроса по полю.

Отдельный реквизит оправдан, когда ключ должен жить независимо от ссылки: его можно переназначить, очистить, перенести на другой элемент при слиянии дублей. Дальше — про этот вариант.

1. Добавляем реквизит-идентификатор в структуру метаданных

Если конфигурация на поддержке (типовая БП, ЗУП, УТ), не снимайте её с поддержки ради одного реквизита. Добавьте его через расширение: заимствуйте нужный справочник или документ и создайте реквизит уже в расширении. Тогда обновления типовой не потребуют ручного сравнения и объединения.

Порядок для своей или снятой с поддержки конфигурации:

  1. Сделайте резервную копию базы : Администрирование → Выгрузить информационную базу в Конфигураторе.
  2. Откройте конфигурацию: Конфигурация → Открыть конфигурацию.
  3. В дереве метаданных найдите объект, например Справочники → Контрагенты, и откройте его двойным щелчком.
  4. Перейдите на вкладку «Данные» и в разделе реквизитов нажмите «Добавить».
  5. Задайте имя без пробелов, например ВнешнийИД или ИдентификаторCRM. Синоним — понятный пользователю: «Идентификатор в CRM».
  6. В поле «Тип» выберите УникальныйИдентификатор. Длину и точность задавать не нужно.

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

У расширения есть свойство «Префикс имён», например Расш1_. Имена новых реквизитов начинайте с него: Расш1_ВнешнийИД. Так поле не столкнётся с одноимённым реквизитом, если фирма-разработчик добавит его в типовую в следующем релизе.

Имя реквизита потом используется в коде, запросах и обменах. Переименовать его позже можно, но придётся править все места, где оно встречается, включая внешние системы, которые читают это поле через OData или HTTP-сервис.

2. Свойства и индексирование поля идентификатора

Реквизит без индекса работает, но поиск по нему в большой таблице будет медленным. Каждая загрузка из внешней системы начинается с вопроса «есть ли уже объект с таким GUID», поэтому индекс нужен почти всегда.

Откройте палитру свойств реквизита (Alt+Enter) и проверьте:

  • 🔎 Индексировать — значение «Индексировать». Вариант «Индексировать с доп. упорядочиванием» нужен, только если по полю строят списки с сортировкой. Для поиска хватает обычного индекса.
  • ✏️ Проверка заполнения — «Не проверять». Поле заполняется кодом, пользователю его вводить не надо.
  • 👁 На форме — выведите поле только для просмотра. Ручная правка GUID почти всегда приводит к рассинхрону с внешней системой.
  • 🔐 Права — если ключ служебный, его можно не показывать на форме вовсе, а смотреть в отладке или отчёте.

Индекс не гарантирует уникальности. Платформа не запретит записать два элемента с одинаковым GUID в реквизите. Проверку дубля нужно писать самому — пример в следующем разделе.

После настройки сохраните конфигурацию и выполните Конфигурация → Обновить конфигурацию базы данных (F7). Для изменения структуры таблиц нужен монопольный доступ к базе: предупредите пользователей и запускайте обновление, когда в базе никто не работает .

3. Автоматическое заполнение идентификатора при записи

Заполнять GUID надёжнее всего в модуле объекта, а не в форме. Модуль объекта срабатывает при любой записи: из формы, из обработки, из обмена. Код формы — только при интерактивной работе.

Откройте модуль объекта (правой кнопкой по справочнику → «Открыть модуль объекта») и добавьте два обработчика:

Процедура ПередЗаписью(Отказ)

	Если ОбменДанными.Загрузка Тогда
		Возврат;
	КонецЕсли;

	Если ВнешнийИД = ПустойУИД() Тогда
		ВнешнийИД = Новый УникальныйИдентификатор;
	КонецЕсли;

	Если ЕстьДубльИдентификатора() Тогда
		Сообщение = Новый СообщениеПользователю;
		Сообщение.Текст = "Идентификатор " + Строка(ВнешнийИД) + " уже занят другим элементом.";
		Сообщение.Сообщить();
		Отказ = Истина;
	КонецЕсли;

КонецПроцедуры

Процедура ПриКопировании(ОбъектКопирования)

	ВнешнийИД = ПустойУИД();

КонецПроцедуры

Функция ПустойУИД()

	Возврат Новый УникальныйИдентификатор("00000000-0000-0000-0000-000000000000");

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

Функция ЕстьДубльИдентификатора()

	Запрос = Новый Запрос(
	"ВЫБРАТЬ ПЕРВЫЕ 1
	|	Т.Ссылка
	|ИЗ
	|	Справочник.Контрагенты КАК Т
	|ГДЕ
	|	Т.ВнешнийИД = &ИД
	|	И Т.Ссылка <> &Ссылка");
	Запрос.УстановитьПараметр("ИД", ВнешнийИД);
	Запрос.УстановитьПараметр("Ссылка", Ссылка);

	Возврат НЕ Запрос.Выполнить().Пустой();

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

Что здесь важно:

  1. Новый реквизит типа УникальныйИдентификатор по умолчанию содержит нулевой GUID 00000000-0000-0000-0000-000000000000. Поэтому пустоту проверяем сравнением с ним.
  2. ПриКопировании сбрасывает ключ у копии. Без этого пользователь копирует контрагента — и у двух элементов оказывается один GUID.
  3. При ОбменДанными.Загрузка = Истина обработчик ничего не делает: обмен сам передаёт готовый ключ, его нельзя перезаписывать.
  4. У документа сигнатура другая: ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения). Тело то же, в запросе — Документ.<Имя>.

💡 Если ключ должен совпадать с GUID ссылки, в ПередЗаписью нового объекта ссылки ещё нет. Получите её заранее: Ссылка = ПолучитьСсылкуНового(); если пусто — вызовите УстановитьСсылкуНового(Справочники.Контрагенты.ПолучитьСсылку()) и возьмите УникальныйИдентификатор() у этой ссылки.

4. Как заполнить идентификатор у уже существующих данных

После обновления структуры у всех старых элементов в новом поле нулевой GUID. Их нужно заполнить один раз — внешней обработкой или обработчиком обновления.

Решите заранее, что писать в поле:

  • 🔁 GUID ссылки — Выборка.Ссылка.УникальныйИдентификатор(). Удобно, если внешняя система уже знает объекты по ссылкам 1С.
  • 🆕 Новый случайный GUID — Новый УникальныйИдентификатор. Когда ключи ещё никуда не передавались.
  • 📥 Ключи из внешней системы — загрузка таблицы соответствий «код/ИНН → GUID» из файла.

Пример серверной процедуры внешней обработки:

&НаСервере
Процедура ЗаполнитьИдентификаторыНаСервере()

	Запрос = Новый Запрос(
	"ВЫБРАТЬ
	|	Т.Ссылка
	|ИЗ
	|	Справочник.Контрагенты КАК Т
	|ГДЕ
	|	Т.ВнешнийИД = &Пустой");
	Запрос.УстановитьПараметр("Пустой",
		Новый УникальныйИдентификатор("00000000-0000-0000-0000-000000000000"));

	Выборка = Запрос.Выполнить().Выбрать();
	Счетчик = 0;

	Пока Выборка.Следующий() Цикл
		Объект = Выборка.Ссылка.ПолучитьОбъект();
		Объект.ВнешнийИД = Выборка.Ссылка.УникальныйИдентификатор();
		Объект.ОбменДанными.Загрузка = Истина;
		Объект.Записать();
		Счетчик = Счетчик + 1;
	КонецЦикла;

	Сообщить("Заполнено элементов: " + Формат(Счетчик, "ЧН=0; ЧГ=0"));

КонецПроцедуры

ОбменДанными.Загрузка = Истина отключает проверки и обработчики модуля объекта. Запись идёт быстрее, а дата изменения и другие поля, которые заполняют обработчики, не трогаются.

Обработка меняет каждый элемент справочника. Запускайте её на копии базы, затем в рабочей — вне рабочего времени. Если в базе настроен обмен, все изменённые элементы попадут в следующий пакет выгрузки: при 50 000 элементах это заметный объём.

Для документов подход тот же, но сначала проверьте на копии, как ведёт себя запись проведённого документа в вашей конфигурации. Движения при Загрузка = Истина не перезаписываются, однако подписки на события и регистрация изменений для обмена всё равно работают.

5. Использование идентификатора во внешних системах и при обмене

Наружу GUID передают строкой: Строка(ВнешнийИД) даёт вид 5f0c2a8e-1b3d-4e7a-9c11-2d6f8a4b0e93. Обратно строку превращают в значение конструктором Новый УникальныйИдентификатор(Строка).

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

Функция НайтиПоВнешнемуИД(ИДСтрокой)

	Попытка
		УИД = Новый УникальныйИдентификатор(ИДСтрокой);
	Исключение
		Возврат Справочники.Контрагенты.ПустаяСсылка();
	КонецПопытки;

	Запрос = Новый Запрос(
	"ВЫБРАТЬ ПЕРВЫЕ 1
	|	Т.Ссылка
	|ИЗ
	|	Справочник.Контрагенты КАК Т
	|ГДЕ
	|	Т.ВнешнийИД = &УИД");
	Запрос.УстановитьПараметр("УИД", УИД);
	Выборка = Запрос.Выполнить().Выбрать();

	Если Выборка.Следующий() Тогда
		Возврат Выборка.Ссылка;
	КонецЕсли;

	Возврат Справочники.Контрагенты.ПустаяСсылка();

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

Где идентификатор пригодится:

  • 🌐 HTTP-сервис — отдаёте JSON с полем id, внешний сайт по нему же присылает изменения.
  • 📊 Стандартный интерфейс OData — реквизит виден как обычное поле объекта, рядом с Ref_Key (GUID ссылки). Не забудьте добавить объект в состав OData.
  • 🔄 Обмен между базами 1С — в правилах обмена ключ подходит для сопоставления объектов, когда ссылки в базах разные.
  • 📄 Загрузка из Excel и CSV — колонка с GUID позволяет обновлять элементы, а не создавать дубли.

Если внешний ключ совпадает со ссылкой 1С, вместо запроса используйте Справочники.Контрагенты.ПолучитьСсылку(УИД). Учтите: метод вернёт ссылку даже на несуществующий объект. Проверить, есть ли он в базе, можно через Ссылка.ПолучитьОбъект() = Неопределено или запросом.

Ошибки при работе с идентификаторами и как их исправить

Диагностика: выберите симптом

Отдельный случай — реквизит типа Строка(36) вместо УникальныйИдентификатор. Он работает, но занимает в базе в несколько раз больше места и принимает любой мусор: пробелы, заглавные и строчные буквы вперемешку, обрезанные значения. Если ключ точно в формате GUID, выбирайте специальный тип.

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

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

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