Про ссылки, уникальные идентификаторы, GUID и не найденные объекты

Одним из основных постулатов теории по программированию в 1С является понятие объектного типа данных, когда мы говорим, что «удаление объекта ссылочного типа из базы данных и затем создание нового объекта в базе с такими же точно реквизитами приведет базу в новое состояние, в отличие от случая с не объектными данными (например записи регистров)». И для начинающих это так.
Но иногда, при решении практических задач, этих безусловно полезных для формирования правильной «картины мира» у новичка знаний
становится недостаточно…

Про ссылки, 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ах можно прочитать здесь:

Руководство по GUID. Часть 1

Руководство по GUID. Часть 2

Руководство по GUID. Часть 3

32 Comments

  1. vcv
    объекта объектного типа

    Гм. А объекты необъектного типа бывают?

    Не путайте помянутых новичков терминологией. Объект может быть переменной объектного типа или экземпляром объектного типа. Но не бывает объектов объектного типа.

    Reply
  2. TSSV

    (1) vcv, Спасибо за проявленный интерес к публикации и заботу о новичках, которую полностью разделяю.

    Позволю себе цитату с ресурса http://v8.1c.ru/:

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

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

    Эта ссылка также хранится в поле базы данных, вместе с остальными данными объекта. Кроме того, ссылка может быть использована как значение какого-либо поля другого объекта. Например, ссылка на объект справочника Контрагенты может быть использована как значение соответствующего реквизита документа ПриходнаяНакладная.»

    И все же думаю Вы правы — вместо «объектного типа» здесь лучше использовать формулировку «ссылочного типа» — так будет понятней о чем идет речь.

    Reply
  3. WKBAPKA

    если честно, я не понял про уникальность… если УИД уникальный в пределах вселенной, т.е. вероятность совпадения невероятно мала, то фактически гарантируется уникальность ссылок в пределах всех информационных баз… это, конечно, если 1С придерживается алгоритма генерации гуида

    Reply
  4. TSSV

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

    Reply
  5. WKBAPKA

    наверное так оно и есть… с одной стороны… а с другой, интересно, получится ли установить две одинаковые ссылки на один и тот же тип данных…

    Reply
  6. dumal

    Замечательная статья. Спасибо Вам за нее

    Reply
  7. Sherlock_kmw

    (5) WKBAPKA, нет не получится. в каждой из таблиц базы UUID является ключевым полем. отсюда и невозможность поиметь две номенклатуры с одним UUID

    Reply
  8. Psylocibine

    А можно ли подменить UUID конкретного объекта?

    Reply
  9. TSSV

    (8) Psylocibine, Подменить UUID конкретного объекта можно, но нужно помнить о ссылках на объект — они станут «битыми». Поэтому решение может быть следующим — создаем копию объекта с нужным УИДом, с помощью универсальной обработки «Поиск и замена значений» заменяем ссылки старого объекта на новый, удаляем старый объект. Так же мне приходилось решать задачу перевода метода синхронизации ряда справочников (контрагенты, номенклатура и пр.) с синхронизации по коду на синхронизацию по внутреннему идентификатору в работающей УПП (обмен был с БП) — то есть необходимо было массово заменить УИДы у большого количества элементов. Я поступил следующим образом — сделал полную выгрузку ИБ штатными механизмами УПП — «Выгрузка данных в идентичную конфигурацию» , в сформированном XML файле выгрузки сделал замену GUIDов (предварительно сформировав файл соответствия GUIDов), после чего загрузил переработанный файл выгрузки в пустую базу. Файл выгрузки редактировался как обычный текстовый файл, в каждой строке которого происходил поиск заменяемого GUIDа среди набора подлежащих замене и собственно сама замена. Метод себя оправдал — на операцию ушло несколько часов (не считая подготовки конечно) и в дальнейшем проблем с обменом не возникало.

    Reply
  10. lsp71

    Хорошая статья. И написана понятным языком.

    Reply
  11. petrovaUL

    позновательно

    Reply
  12. bforce
    Может ли в базе 1С существовать два объекта с одинаковыми уникальными идентификаторами? Да, теоретически могут, но не в одной таблице (не в одном типе метаданных). То есть, мы можем иметь, например, элемент справочника «Номенклатура» и элемент справочника «Контрагенты» с одинаковым УИД и это нормально (на работоспособности системы это не скажется).

    Вот здесь написано иначе

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

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

    При условии, конечно, что вы будете использовать внутренние механизмы для генерации УИДов.

    Reply
  13. Lo1jke

    Спасибо, очень помоги, как раз занимался переносом XML нетипизированной партянки и нужно было насильно присваивать ГУИД.

    Reply
  14. TSSV

    (13) Lo1jke, (10) рад что пригодилось, спасибо за отзывы!

    Вот еще на эту тему: http://infostart.ru/public/192055/

    Reply
  15. volconok27

    Отличная статья. Как раз кстати. Спасибо

    Reply
  16. chmv

    Спаасибо Интересно

    Reply
  17. MaiorovYury

    Спасибо!

    Reply
  18. AlexO

    (0)

    При этом, в структуре надписи «Объект не найден …» содержится GUID удаленной ссылки.

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

    Reply
  19. AlexO

    (0)

    Итак, миф развенчан, но признаем, что он был полезен нам в начале пути.

    Вы ничего не развенчали, а еще больше запутали новичков, для которых, якобы, все и «развенчивали».

    Вы гарантируете, что после удаления ссылки те данные, на которые она ссылалась — осталось в целости и сохранности? Нет.

    Вы гарантируете, что все подчиненные объекты «внутри» удаленного — остались на месте? Нет.

    Так называемое «восстановление», да еще и громко названное

    приведения системы в прежнее состояние после удаления объекта ссылочного типа

    — не более чем создание и подгонка новых объектов под старые (битые) ссылки, а не восстановление старых объектов. Старые (и их содержимое) — потеряны навсегда.

    А хотите «обмануть» систему — да пожалуйста, не надо ничего изобретать: создаете новый объект, удаляете старую ссылку, заменяете все старые — на новые.

    Вуаля, ссылки восстановлены!

    Т.е. статья написана «умно», но много воды, напущено тумана (для умности статьи?), и, главное, выводы сделаны совершенно неправильные (или двусмысленные — видимо, сам не разобрался).

    Reply
  20. AlexO

    (0)

    Может ли в базе 1С существовать два объекта с одинаковыми уникальными идентификаторами? Да, теоретически могут, но не в одной таблице (не в одном типе метаданных).

    Это сугубо Ваши домыслы.

    1С ищет объект по ссылке, а не по «ссылка+тип данных», и что она должна вернуть, если по ссылке — два объекта?

    Была теория, что 1С «зашифровала» тип даннных в ссылке, но пока она не получила ни подтверждения, ни полного отпровержения, т.к. ссылки формируются «подряд» (документ — ссылка №1, справочник — ссылка №2, документ — ссылка №3, ссылки по-порядку, последовательно, формируются), однако, и опровержение «зашифрованности» не получено от 1С.

    Reply
  21. AlexO

    (12) bforce,

    Вот здесь написано иначе

    Страничка удалена с ИТС.

    Reply
  22. AlexO

    (0)Tsaregorodtsev,

    создавать новую ссылку:

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

    нужно так:

    УИД = Новый УникальныйИдентификатор();
    
    НовыйЭлемент = Справочники[ИмяМетаданных].СоздатьЭлемент();
    
    НоваяСсылка = Справочники[ИмяМетаданных].ПолучитьСсылку(УИД);

    Все.

    И не надо тыркать по десять раз ссылку туда-сюда.

    Reply
  23. AlexO

    (0)Tsaregorodtsev,

    А как ссылка соотносится с уникальным идентификатором (далее УИД)

    Это UUID:

    Объект не найден (48:b3e2001617ec3f2a11e1912c787ec129)

    Это GIUD (назван «УИД» в 1С):

    787ec129-912c-11e1-b3e2-001617ec3f2a:

    А у вас туман один клубится в статье.

    Reply
  24. pavelyar

    Нет штатного средства поиска по GUID в конфиграциях и это очень плохо,под УФ тоже обработок не найти это беда…

    Reply
  25. AlexO

    (24) pavelyar,

    Нет штатного средства поиска по GUID в конфиграциях

    GUID как таковой вообще не используется в платформе 1С. Ссылки хранятся в формате UUID. Что и подтвержадет ошибка «Объект не найден (48:b3e2001617ec3f2a11e1912c787ec129)».

    Reply
  26. Videon

    Мне кажется, что «Ссылка — это тип данных,» взрывает мозг новичкам, ибо это не тип данных. Вот выдержка с сайта 1С: «Ссылка — это значение, однозначно характеризующее объекты базы данных (элементы справочников, документы и так далее).

    Для хранения ссылок предназначены типы встроенного языка СправочникСсылка.<имя>, ДокументСсылка.<имя> и так далее.»

    Ссылка — это свойство объекта БД (например, экземпляра справочника Номенклатура). Тип данных этого свойства = СправочникСсылка.<Имя справочника> (например, СправочникСсылка.Номенклатура). То же самое есть в Синтакс-помощнике.

    Так или не так?

    Reply
  27. TSSV

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

    Reply
  28. Big Fox

    GUID и UUID взаимозаменяемы

    Reply
  29. Adam12345678

    Здравствуйте. Вопрос к знатокам. Если мы перенесли информацию из одной базы в другую, к примеру, номенклатуру с использованием конвертации данных, оставив уникальный идентификатор одинаковым для источника и приёмника, есть ли теоретическая возможность того, что при создании нового элемента в базе приёмнике система сгенерирует уникальный идентификатор такой же как уже имеющийся, перенесенный из другой базы и тем самым «затрет» ранние данные?

    Reply
  30. CheBurator

    (30) ну так сначала, наверное, в базе приемнике ищем СУЩЕСТВУЮЩИЙ элемент, если не нашли — тогда создаем… как здесь что-то может затереть?

    Reply
  31. TSSV

    (30) Нет, этого не может произойти, так как ссылка — кластерный индекс таблицы справочника на уровне СУБД, элемент с существующим в базе УИДом ссылки не будет записан. Можете проверить с помощью конструкции:

    УИД = Новый УникальныйИдентификатор(ЗаданныйУИД);

    НоваяСсылка = Справочники[ИмяМетаданных].ПолучитьСсылку(УИД);

    НовыйЭлемент = Справочники[ИмяМетаданных].СоздатьЭлемент();

    НовыйЭлемент.УстановитьСсылкуНового(НоваяСсылка);

    НовыйЭлемент.Записать();

    Reply
  32. Adam12345678

    (32) Спасибо.

    Reply

Leave a Comment

Ваш адрес email не будет опубликован. Обязательные поля помечены *