Про ссылки, GUID, уникальные идентификаторы и ненайденные объекты.
Одним из основных постулатов теории программирования в 1С является понятие объектного типа данных, когда мы говорим, что «удаление объекта ссылочного типа из базы данных и затем создание нового объекта в базе с такими же точно реквизитами приведет базу в новое состояние, в отличие от случая с необъектными данными (записи регистров и пр.)». И для новичков это так.
Но иногда, при решении практических задач, этих безусловно полезных для формирования правильной «картины мира» новичка знаний становится недостаточно.
Итак, что же такое ссылка с точки зрения 1С? Ссылка - это тип данных, однозначно идентифицирующий объект в системе. А как ссылка соотносится с уникальным идентификатором (далее УИД) , получаемым методом УникальныйИдентификатор()? УИД - это по сути свойство ссылки с типом УникальныйИдентификатор, строковое представление которого является 16-ричным числом и выглядит примерно так:
6a09f20a-8de6-11e1-b3e1-001617ec3f2a
К слову, УИД пустой ссылки всегда такой:
00000000-0000-0000-0000-000000000000
Итак, ссылка логически состоит из двух частей – имени соответствующего объекта метаданных (тип ссылки), например «Справочник.Контрагенты», и УИДа, являющегося по своей природе GUIDом (об этом далее). Уникальность имени объекта метаданных контролируется платформой – вы не сможете создать двух справочников с одинаковым именем. Таким образом, ссылка является уникальной сущностью в пределах базы данных и это свойство (уникальности) обеспечивается двумя составляющими.
Теперь, для полноты картины, поговорим о том, что такое GUID. По данным сайта wikipedia.org:
«GUID (Globally Unique Identifier) — статистически уникальный 128-битный идентификатор. Его главная особенность — уникальность, которая позволяет создавать расширяемые сервисы и приложения без опасения конфликтов, вызванных совпадением идентификаторов. Хотя уникальность каждого отдельного GUID не гарантируется, общее количество уникальных ключей настолько велико (2128 или 3,4028×1038), что вероятность того, что в мире будут независимо сгенерированы два совпадающих ключа, крайне мала. Тем не менее на системе Windows'95 GUID идентификаторы закладки свойств для ярлыка запуска DOS программ(.pif) и программы Zip Magic совпадали.»
То есть, новые GUIDы получаются генерацией случайных чисел в диапазоне, сопоставимом с количеством атомов во Вселенной (на самом деле в платформе 1С используется другой способ формирования GUIDов, но пока для простоты давайте не будем на этом заостряться, подробнее об этом в конце публикации).
Таким образом, мы теперь понимаем, что при создании нового элемента объектного типа, в платформе 1С запускается специальный генератор случайных чисел и получается GUID, который и записывается в качестве УИДа ссылки.
Может ли в базе 1С существовать два объекта с одинаковыми уникальными идентификаторами? Да, теоретически могут, но не в одной таблице (не в одном типе метаданных). То есть, мы можем иметь, например, элемент справочника «Номенклатура» и элемент справочника «Контрагенты» с одинаковым УИД и это нормально (на работоспособности системы это не скажется).
Можно ли зная УИД найти объект в базе? В общем случае нельзя, нужно дополнительно знать где искать – то есть таблицу данных, имя которой определяется именем объекта метаданных. Но, зная о том, что вероятностью совпадения GUID можно пренебречь, то на практике можно осуществлять поиск ссылки по УИД (например, анализируя файл выгрузки данных в формате XML), плюс учесть возможности программного создания объектов с заданным GUIDом, речь о которых пойдет ниже.
С теорией мы разобрались и теперь проведем небольшой эксперимент. Развенчаем "миф" о невозможности приведения системы в прежнее состояние после удаления объекта ссылочного типа. Использовать будем исключительно средства платформы 1С.
Во вложении пример обработки (для 8.2) с процедурой "УдалитьВосстановитьЭлемент", которая сначала удаляет элемент справочника по передаваемой ссылке, а потом создает новый такой же элемент (для простоты предполагается, что справочник не содержит табличных частей). При этом, после удаления, ссылки на элемент становятся "битыми" (объект не найдент...), а после воссоздания опять становятся "нормальными".
Теперь немного о практическом применении полученных знаний. Всем известно такое явление, как «Объект не найден..», которое как известно возникает при удалении объектов без контроля ссылочной целостности. При этом, в структуре надписи «Объект не найден …» содержится GUID удаленной ссылки. Вот пример соответствия отображения "битой ссылки" и GUIDа этой ссылки:
Объект не найден (48:b3e2001617ec3f2a11e1912c787ec129)
787ec129-912c-11e1-b3e2-001617ec3f2a:
Здесь видно, что структура отображения ссылки и GUID соответствуют друг другу, но не совпадают. Мы сейчас не будем на этом останавливаться, скажем только, что восстановить «битую» ссылку можно и этому посвящен ряд отдельных публикаций, например вот эта: Реанимация битых ссылок
Анализируя XML файлы обмена, мы так же можем встретить знакомые уже GUIDы, которые можно в случае необходимости изменять (такие задачи конечно же редки, но иногда могут встретиться).
Так же, иногда встречаются задачи, когда нам нужно создать и записать сразу два элемента справочника, где один элемент одновременно является владельцем другого и ссылается на него (например, элемент справочника "Номенклатура" с реквизитом "Основная единица измерения" с типом справочник "Единицы измерения", который в свою очередь подчинен номенклатуре).
Используя конструкции:
УИД = Новый УникальныйИдентификатор();
НоваяСсылка = Справочники[ИмяМетаданных].ПолучитьСсылку(УИД);
НовыйЭлемент = Справочники[ИмяМетаданных].СоздатьЭлемент();
НовыйЭлемент.УстановитьСсылкуНового(НоваяСсылка);
мы можем организовать запись каждого из элементов за один раз.
В задачах обмена данными с помощью конфигурации «Конвертация данных», мы настраиваем соответствие типов в базах источника и приемника и в качестве метода синхронизации можем указать – «По внутреннему идентификатору объекта источника». Здесь «внутренний идентификатор» не что иное как УИД передаваемой ссылки. Но, так как только УИДа для однозначной идентификации объекта недостаточно, передается еще и информация о типе данных приемника, например «СправочникСсылка.Склады», которая используется для поиска нужного элемента (или создания нового). При этом, новые элементы в базе приемника создаются с УИДами базы источника. И здесь возможна ситуация, когда, например, при миграции одного документа источника в пару документов приемника (приходная накладная из базы источника загружается в пару документов приходная накладная и приходный ордер приемника), УИДы у создаваемой в приемнике пары документов будут одинаковыми и равны УИДу документа в базе источника. Как мы уже говорили выше, это вполне нормально.
Замечу, что использовать данные механизмы нужно крайне осторожно, помня о возможных последствиях.
В начале публикации для упрощения понимания основной идеи мы считали, что GUIDы формируются как случайные числа в очень большом диапазоне, к тому же сама идея своей красотой заслуживает к себе внимания. Но, как уже упоминалось ранее, на самом деле в случае платформы 1С это не так - при формировании GUIDов используется время, о чем говорит "1" в первой позиции третьей секции (при случайной генерации на этой позиции "4"):
787ec129-912c-11e1-b3e2-001617ec3f2a
И связи с этим у нас появляется еще одна интересная возможность - получения времени генерации УИДа ссылки. Вот ссылка на публикацию с обработкой получения времени ссылки:
Получить дату создания документа или элемента справочника (по UID)
Подробнее о GUIDах можно прочитать здесь: