Содержание
Что такое GUID и где он используется в 1С
GUID расшифровывается как Globally Unique Identifier, и представляет собой статистически уникальный 128-битный идентификатор. Вероятность того, что где-нибудь в мире будут независимо сгенерированы два идентичных ключа, исчезающе мала, так как общее количество возможных ключей составляет 2 в 128 степени. В 1С GUID используется в ссылочных типах данных, а также уникальный идентификатор присваивается каждому вновь образуемому типу данных при добавлении метаданных конфигурации. На примере метаданных обработки: GUID есть у самого объекта метаданных, у объекта данных, и у менеджера этой обработки. Эти идентификаторы используются в механизмах сериализации, а также в механизмах сравнения-объединения конфигураций.
Получить идентификатор у ссылочного объекта можно, а вот программного доступа к GUID метаданных нет – но можно посмотреть идентификаторы образованных типов, выгрузив конфигурацию в файлы, либо получив сериализованное представление нужного объекта.
Устройство GUID в 1С на примерах
Строковое представление GUID – это строка из 32 шестнадцатеричных цифр, состоящая из четырех частей, разделенных дефисами. Уникальные идентификаторы делятся на пять версий. В зависимости от версии GUID, его четыре части формируются по-разному, и содержат разную информацию. Подробное строение GUID описано в спецификации UUID – универсального уникального идентификатора, реализацией которого является GUID.
- time-based version. Данная версия содержит информацию о времени генерации GUID и MAC-адресе узла (устройства), на котором идентификатор был сгенерирован
- DCE Security version (POSIX UIDs) – также содержит MAC-адрес, но из-за особенностей генерации не подходит в случаях, когда GUID необходимо генерировать чаще чем раз в 7 минут
- name-based version (MD5 hashing) – GUID генерируется путем хэширования идентификатора пространства имен и имени. Хэширование производится по алгоритму MD5
- randomly generated version – случайно генерируемый GUID
- name-based version (SHA-1 hashing) – то же что и версия 3, только в качестве алгоритма хэширования используется SHA-1
GUID для объектов ссылочных типов, которые генерируются в момент записи объекта, относятся к time-based версии, а идентификаторы объектов метаданных, типов значений, предопределенных элементов, созданных в конфигураторе, и полученные методом Новый УникальныйИдентификатор() относятся к версии 4 – случайно генерируемые.
Вооружившись этими знаниями, займемся исследованием GUID-ов, которые мы можем получить в 1С. В качестве объектов для опытов создадим обработку РаботаСГУИД и справочник ТестовыйСправочник. В обработке добавим команду, а в серверном обработчике этой команды пропишем следующий код:
&НаСервере Процедура ПолучитьСериализованноеПредставлениеНаСервере() МенеджерОбработки = Обработки.РаботаСГУИД; Сообщить(ЗначениеВСтрокуВнутр(МенеджерОбработки)); МенеджерОбъектаОбработки = Обработки.РаботаСГУИД.Создать(); Сообщить(ЗначениеВСтрокуВнутр(МенеджерОбъектаОбработки)); Для Сч = 1 по 3 Цикл Эл = Справочники.ТестовыйСправочник.СоздатьЭлемент(); Эл.Записать(); Сообщить(Эл.Ссылка.УникальныйИдентификатор()); Эл.Удалить(); КонецЦикла; // У объекта языка "Метаданные" GUID всегда один и тот же - 9fb58eea-17f2-4200-b105-b288d62f4303 Сообщить(ЗначениеВСтрокуВнутр(Справочники.ТестовыйСправочник.СоздатьЭлемент().Метаданные())); Сообщить(ЗначениеВСтрокуВнутр(Метаданные.Обработки.РаботаСГУИД)); КонецПроцедуры
Метод ЗначениеВСтрокуВнутр сериализует объекты языка в строку. В рассматриваемом примере в окно сообщений будут выведены следующие данные:
{“#”,ff798e9f-e182-4a0f-af78-224dbb45de69,
{0}
}
{“#”,609fe03c-dbf8-4f78-835d-178eed7ceb70}
8e1f9db8-4be2-11ed-a101-2c4d5450919d
8e1f9db9-4be2-11ed-a101-2c4d5450919d
8e1f9dba-4be2-11ed-a101-2c4d5450919d
{“#”,9fb58eea-17f2-4200-b105-b288d62f4303}
{“#”,9fb58eea-17f2-4200-b105-b288d62f4303}
Если выгрузить конфигурацию в файлы и открыть файл с обработкой РаботаСГУИД, можно увидеть, что идентификаторы экземпляра обработки и менеджера обработки действительно соответствуют тому, что мы получили в результате сериализации:
Разберем структуру GUID на примере идентификатора, созданного в момент записи элемента справочника:
8e1f9db8-4be2-11ed-a101-2c4d5450919d
GUID записывается по группами шестнадцатеричных чисел по схеме 8-4-4-4-12. В случае, когда используется версия 1 (основанная на времени), значение групп будет следующим:
8e1f9db8-4be2 – отметка времени Timestamp
11ed – первые бита – это версия GUID, в нашем случае 1. Остальные – формируют оставшуюся часть отметки времени
a101 – вариант GUID И Clock Sequence
2c4d5450919d – MAC-адрес узла (Node)
Так все-таки, можно ли упорядочивать по GUID?
При записи объектов в 1С версия 1 используется не просто так. Случайные GUID очень плохо кластеризуются, дерево поиска получается максимально широкое, и для того, чтобы оптимизировать операции поиска / вставки, используется комбинированный вариант генерации GUID. Использование отметки времени позволяет сделать ключи более сгруппированными и уменьшить ширину B-дерева. При этом последовательное их возрастание в общем случае не гарантируется. В рамках одного сеанса генерируемые GUID формируются порциями по 32 штуки, и в рамках этой порции они действительно могут быть последовательными. Если объекты одновременно записываются в нескольких параллельных сеансах, их GUID могут быть упорядочены в рамах одного сеанса, одного типа данных, и одного пула из 32 идентификаторов.
Сами уникальные идентификаторы в СУБД хранятся в виде двоичных данных Binary (16), и сортируются побитово как бинарные данные. Попытки использовать GUID для упорядочивания по отметке времени – от лукавого. Во-первых, на оси времени в пределах одной секунды документы разных типов в любом случае не будут располагаться хронологически. Во-вторых, документы одного типа также не будут в общем случае, если они заводятся в рамках разных параллельных сеансов.
Вывод, подкрепленный цитатой Бориса Нуралиева: использовать GUID для хронологического упорядочивания объектов на оси времени в общем случае нельзя!
“Механизм генерации ссылок обеспечивает только их уникальность. Возрастающая последовательность при их генерации не обеспечивается.” (c)
Получить время из GUID
&НаСервереБезКонтекста Функция ОтметкаВремениГУИД(ГУИД) // В спецификации UUID для версии 1 дата содержится в первых трех группах из схемы 8-4-4-4-12 // Например, рассмотрим GUID 8e1f9db8-4be2-11ed-a101-2c4d5450919d // Дата содержится в первых символах, 8e1f9db8-4be2-11ed которые нужно переставить в обратном порядке: 11ed-4be2-8e1f9db8 Строка16 = Сред(ГУИД, 15, 4) + Сред(ГУИД, 10, 4) + Сред(ГУИД, 1, 8); // Убираем знаки "-"(дефисы) Строка16 = СтрЗаменить(Строка16, "-", ""); // Убираем первый символ, так как по спецификации это - номер версии стандарта. Строка15 = Сред(Строка16, 2); // Получаем 60-битную отметку времени : ed4be28e1f9db8 // Преобразуем к десятичному числу ЧислоСек = 0; Для Позиция = 1 По СтрДлина(Строка15) Цикл ЧислоСек = ЧислоСек + Найти("123456789abcdef", Сред(Строка15, Позиция, 1))*Pow(16, СтрДлина(Строка15) - Позиция); КонецЦикла; ЧислоСек = ЧислоСек / 10000000; // Прибавляем к дате начала Григореанского календаря Возврат Дата(1582, 10, 15, 00, 00, 00) + ЧислоСек + СмещениеСтандартногоВремени() + СмещениеЛетнегоВремени();; КонецФункции
Разбор GUID из ссылки
В 1С из ссылки можно получить тип уникального идентификатора (его версию), время и MAC-адрес узла для версии 1.
&НаСервереБезКонтекста Функция ВерсияГУИД(ГУИД) // Номер версии содержится в старшем байте седьмого октета Версия = Число(Сред(ГУИД, 15, 1)); СоответствиеВерсий = Новый Соответствие; СоответствиеВерсий.Вставить(0, "NIL GUID"); СоответствиеВерсий.Вставить(1, "Version 1. (Time-based)"); СоответствиеВерсий.Вставить(2, "DCE Security (POSIX)"); СоответствиеВерсий.Вставить(3, "Version 3. Name-based (MD5 hashing)"); СоответствиеВерсий.Вставить(4, "Version 4. Random"); СоответствиеВерсий.Вставить(5, "Version 5. Name-based (SHA-1 hashing)"); Возврат СоответствиеВерсий.Получить(Версия); КонецФункции
&НаСервереБезКонтекста Функция УзелГУИД(ГУИД) // В маске UUID 8-4-4-4-12 для версии 1 MAC-адрес содержится в последней 12-значной группе. Строка12 = Сред(ГУИД, 25); // Разделим на октеты Результат = ""; Для Позиция = 1 По СтрДлина(Строка12) Цикл Если Позиция % 2 = 1 Тогда Результат = Результат + " "; КонецЕсли; Результат = Результат + ВРЕГ(Сред(Строка12,Позиция,1)); КонецЦикла; Результат = СтрЗаменить(СокрЛП(Результат), " ", ":"); Возврат Результат; КонецФункции
&НаКлиенте Процедура ВывестиИнформациюПоГУИД(Знач ГУИД, Знач СсылкаНаЭлементСправочника) Сообщить("Ссылка: " + СсылкаНаЭлементСправочника); Сообщить("GUID: " + ГУИД); Сообщить("Дата создания: " + ОтметкаВремениГУИД(ГУИД)); Сообщить("Версия: " + ВерсияГУИД(ГУИД)); Сообщить("MAC-адрес хоста: " + УзелГУИД(ГУИД)); КонецПроцедуры
Для любой пустой ссылки идентификатор всегда будет 00000000-0000-0000-0000-000000000000. По идентификатору определить тип значения объекта в общем случае невозможно. Более того, объекты разных типов могут иметь одинаковые идентификаторы даже в пределах одной информационной базы (Например, элементы справочников Номенклатура и Контрагенты), так как их уникальность будет обеспечиваться типами значений (ключи хранятся физически в разных таблицах, следовательно, между собой не пересекаются).
Получение GUID в запросе
В версии платформы 8.3.22 планируется реализовать в языке запросов метод УникальныйИдентификатор(СсылкаНаОбъект) для получения GUID непосредственно в результат запроса.
В остальных же случаях стандартное решение – обойти результат запроса и использовать метод ссылки УникальныйИдентификатор() в цикле.
Как узнать GUID-ы метаданных?
Программного доступа к идентификаторам метаданных у разработчика нет. Тем не менее, можно выгрузить конфигурацию в файлы, и проанализировать их содержимое. Кроме того, сериализуемые объекты можно преобразовать в сериализованную строку и в этой строке узнать идентификатор, например, для объекта обработки или ее менеджера. Разумеется, можно частично это дело автоматизировать, написать скрипты выгрузки конфигурации в файлы, парсинга этих файлов и т.д.
Особенности представления GUID в 1С
Ссылка в 1С представляет собой комбинацию номера таблицы в СУБД и уникального идентификатора. Рассмотрим пример:
&НаСервере Процедура РазобратьСсылкуНовогоНаСервере() ТестСсылка = Справочники.ТестовыйСправочник.ПолучитьСсылку(Новый УникальныйИдентификатор()); ГУИД= ТестСсылка.УникальныйИдентификатор(); ВывестиИнформациюПоГУИД(ГУИД, ТестСсылка); КонецПроцедуры
Дата создания: 23.11.2963 20:26:48 Ссылка: <Объект не найден> (166:adc8d3f7c50e35a2460c6676bb9ce99d) GUID: bb9ce99d-6676-460c-adc8-d3f7c50e35a2 Версия: Version 4. Random MAC-адрес хоста: D3:F7:C5:0E:35:A2
Обратите внимание, т.к. версия формата 4 – все данные представляют собой случайный набор символов, соответственно, ни даты ни мак-адреса случайный GUID не содержит.
Представление ссылки в 1С – это UUID, который записан отличным образом от GUID этой же ссылки. Перед идентификатором выводится номер таблицы в СУБД, в нашем случае 166. Из UUID можно восстановить GUID, и наоборот. Для этого следует разделить запись на октеты (последовательности из 4 символов) и выстроить их в нужном порядке.
GUID:
- 1 – bb9c
- 2 – e99d
- 3 – 6676
- 4 – 460c
- 5 – adc8
- 6 – d3f7
- 7 – c50e
- 8 – 35a2
UUID ссылки:
- 5 – adc8
- 6 – d3f7
- 7 – c50e
- 8 – 35a2
- 4 – 460c
- 3 – 6676
- 1 – bb9c
- 2 – e99d