Почему после вызова УстановитьСсылкуНового ссылка объекта не меняется и сравнение возвращает Ложь?

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

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

Однако, при попытке сразу же проверить результат присвоения через свойство Ссылка, мы получаем неожиданный результат: ссылка объекта остается пустой, а сравнение с назначенным значением возвращает Ложь. В этой статье мы подробно разберем, почему так происходит, как устроена архитектура объектной модели 1С в этом аспекте, и как правильно работать с ссылками новых объектов.

Суть проблемы и пример кода

Рассмотрим ситуацию, которая вызывает недоумение. Мы создаем новый объект (например, элемента справочника или документа), генерируем для него новую уникальную ссылку и пытаемся установить её объекту.

Давайте взглянем на код, который демонстрирует проблему:


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

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

// Пытаемся установить эту ссылку нашему новому объекту
НовыйОбъект.УстановитьСсылкуНового(НоваяСсылка);

// ПРОВЕРКА
// Мы ожидаем, что НовыйОбъект.Ссылка теперь равна НоваяСсылка
РезультатСравнения = (НовыйОбъект.Ссылка = НоваяСсылка);

// Выводим результат
Сообщить("Равны ли ссылки? " + РезультатСравнения); // Выведет: ЛОЖЬ

Возникает закономерный вопрос: почему платформа игнорирует нашу команду? Мы ведь явно вызвали метод установки ссылки. Чтобы ответить на этот вопрос, нам необходимо углубиться в то, как платформа 1С управляет объектами в памяти и в базе данных.

Разбираем механику свойства «Ссылка»

Главная причина такого поведения кроется в природе свойства Ссылка у прикладных объектов (СправочникОбъект, ДокументОбъект и т.д.).

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

Давайте проанализируем это детально:

  1. Когда вы создаете объект в памяти (через СоздатьЭлемент() или СоздатьДокумент()), он существует только в оперативной памяти сервера (или клиента, в зависимости от контекста). В таблицах базы данных записи еще нет.
  2. Свойство Объект.Ссылка — это по сути "проекция" физического существования записи в БД. Это не просто переменная, которую можно менять. Это идентификатор, под которым объект уже лежит в базе.
  3. Поскольку объекта в базе нет, платформа честно сообщает вам об этом, возвращая Справочник.ИмяСправочника.ПустаяСсылка при обращении к Объект.Ссылка.

Именно поэтому выражение НовыйОбъект.Ссылка = НоваяСсылка возвращает Ложь. Вы сравниваете Пустую Ссылку (которая хранится в свойстве незаписанного объекта) с Конкретной Ссылкой (которую вы сгенерировали и храните в переменной).

Как работает метод УстановитьСсылкуНового?

Если свойство Ссылка доступно только для чтения и отражает состояние базы данных, то что же делает метод УстановитьСсылкуНового()? Куда девается переданное нами значение?

Метод УстановитьСсылкуНового(<Ссылка>) работает как механизм отложенного назначения. Рассмотрим алгоритм его действия:

  1. Буферизация: При вызове метода платформа не пишет значение напрямую в свойство Ссылка. Вместо этого она сохраняет переданный GUID в специальную внутреннюю служебную переменную объекта (можно представить это как скрытый "карман" или "буфер").
  2. Ожидание записи: Объект продолжает жить в памяти с пустой "официальной" ссылкой, но с заполненным "буфером" будущей ссылки.
  3. Момент записи: Когда вы вызываете метод Объект.Записать(), платформа проверяет этот внутренний буфер.
    • Если буфер пуст: Платформа сама генерирует новый GUID в момент записи.
    • Если буфер заполнен (был вызван УстановитьСсылкуНового): Платформа берет GUID из буфера и пытается выполнить команду INSERT в базу данных именно с этим идентификатором.
  4. Фиксация результата: Только после успешного завершения транзакции записи, свойство Объект.Ссылка обновляется и начинает возвращать тот самый GUID, который мы установили ранее.

Таким образом, УстановитьСсылкуНового — это своего рода "бронирование" идентификатора, который будет применен только в момент фактического рождения записи в базе данных.

Как правильно проверить установленную ссылку?

Если Объект.Ссылка бесполезна до записи, как же нам убедиться, что мы всё сделали правильно и объект "запомнил" нужный идентификатор? Для этого существует парный метод — ПолучитьСсылкуНового().

Давайте посмотрим, как правильно работать с этими методами в коде:


НовСсылка = Справочники.Товары.ПолучитьСсылку();
ОбъектТовар = Справочники.Товары.СоздатьЭлемент();

// "Кладем" ссылку в буфер
ОбъектТовар.УстановитьСсылкуНового(НовСсылка);

// ПРОВЕРКА НЕПРАВИЛЬНАЯ
// ОбъектТовар.Ссылка все еще Пустая!
Если ОбъектТовар.Ссылка = НовСсылка Тогда
    // Сюда мы не попадем
КонецЕсли;

// ПРОВЕРКА ПРАВИЛЬНАЯ
// "Достаем" ссылку из буфера для проверки
УстановленнаяСсылка = ОбъектТовар.ПолучитьСсылкуНового();

Если УстановленнаяСсылка = НовСсылка Тогда
    Сообщить("Ура! Ссылка успешно назначена и будет применена при записи.");
КонецЕсли;

Метод ПолучитьСсылкуНового() возвращает именно то значение, которое было передано в УстановитьСсылкуНового(). Если метод установки не вызывался, функция вернет Неопределено (или пустую ссылку, в зависимости от контекста реализации, но чаще используется для проверки факта ручной установки).

Вопрос уникальности и транзакций

Еще один важный аспект, который обсуждался в теме — гарантия уникальности. Почему платформа не присваивает ссылку сразу?

Дело в том, что уникальность ссылки проверяется только при записи объекта. Даже если вы сгенерировали GUID и установили его через УстановитьСсылкуНового, это не гарантирует, что в базе данных уже не существует объекта с таким же идентификатором (например, созданного в другой сессии или загруженного через обмен секундой ранее).

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

Практическое применение: зачем это нужно?

Рассмотрим сценарии, где использование связки ПолучитьСсылку() + УстановитьСсылкуНового() является обязательным.

1. Обмен данными (XML, JSON, веб-сервисы)

Это самый частый случай. Когда вы загружаете данные из другой базы 1С или внешней системы, вам критически важно сохранить Уникальный Идентификатор (UUID) объекта, чтобы при повторной загрузке система нашла этот объект, а не создала дубль. Вы читаете UUID из файла, генерируете по нему ссылку и назначаете её новому объекту перед записью.

2. Создание связанных объектов в одной транзакции

Представьте, что вам нужно создать документ "Заказ" и сразу же создать запись в регистре сведений или подчиненный справочник, который ссылается на этот "Заказ". Но "Заказ" еще не записан!

В этом случае вы:

  1. Заранее генерируете ссылку для Заказа: СслыкаЗаказа = Документы.Заказ.ПолучитьСсылку();
  2. Присваиваете её создаваемому объекту Заказа: ОбъектЗаказ.УстановитьСсылкуНового(СсылкаЗаказа);
  3. Используете переменную СсылкаЗаказа для заполнения реквизитов в подчиненных объектах.
  4. Записываете всё единым блоком.

Без этого механизма вам пришлось бы сначала записать Заказ (чтобы получить его ссылку), и только потом создавать подчиненные данные, что не всегда удобно или допустимо с точки зрения логики транзакции.

Резюме

Подведем итог нашему исследованию:

← На главную