Добрый день!
Генерация уникального детерминированного ключа набора данных - это процесс создания уникального идентификатора, который можно однозначно связать с конкретным набором данных. Ключ должен быть детерминированным, то есть всегда одинаковым для одинаковых входных данных, чтобы гарантировать стабильность и консистентность идентификации данных.
Для чего это нужно программисту 1С? Я использовал этот алгоритм для генерации уникальных идентификаторов строк табличной части в документе. В данном документе строки ТЧ группируются по 11 реквизитам, что исключает возможность добавления двух разных строк с одинаковым набором значений этих реквизитов. После вычисления детерминированного ключа, я уверен, что для одинакового набора данных ключ будет всегда одинаковым. Мне нужно было хранить дополнительную информацию по каждой строке документа в РС, и вместо того, чтобы делать 11 измерений, я сделал 2 - ссылка на документ и UUID строки, что позволило значительно упростить дальнейшую работу с ним.
В моей реализации генерируется UUID v5 для произвольного набора ссылок БД или строк.
Если вызывается UUID для ссылок, то сначала запросом выбираются их строковые представления УИД, а затем идет генерация ключа.
// Функция - Уникальный идентификатор набора ссылок. Ключ записи.
//
// Параметры:
// СписокUUID - Массив Из Ссылка - Массив со ссылками на объекты БД
// ВозвращатьКакУИД - Булево - определяет, возвращать ли результат как УникальныйИдентификатор. Если Ложь - возвращается строкой
//
// Возвращаемое значение:
// Строка, УникальныйИдентификатор - Ключ записи для некоторого набора ссылок
//
Функция УникальныйИдентификаторНабораСсылок(СписокСсылок, ВозвращатьКакУИД = Ложь) Экспорт
// получаем UUID строкой по ссылкам
ЧастиЗапроса = Новый Массив;
ЧастьЗапросаВыборка =
"ВЫБРАТЬ
| ПРЕДСТАВЛЕНИЕ(УНИКАЛЬНЫЙИДЕНТИФИКАТОР(Ссылка))
|ИЗ
| %ИМЯ ТАБЛИЦЫ%
|ГДЕ
| Ссылка В (&СписокСсылок)
|";
ПерваяСсылка = Истина;
Для Каждого Ссылка Из СписокСсылок Цикл
Если Не ПерваяСсылка Тогда
ЧастиЗапроса.Добавить("
| ОБЪЕДИНИТЬ ВСЕ
|
|");
КонецЕсли;
ПолноеИмяМетаданных = Ссылка.Метаданные().ПолноеИмя();
ЧастиЗапроса.Добавить(СтрЗаменить(ЧастьЗапросаВыборка, "%ИМЯ ТАБЛИЦЫ%", ПолноеИмяМетаданных));
ПерваяСсылка = Ложь;
КонецЦикла;
Запрос = Новый Запрос;
Запрос.Текст = СтрСоединить(ЧастиЗапроса, "");
Запрос.УстановитьПараметр("СписокСсылок", СписокСсылок);
Возврат УникальныйИдентификаторНабораСтрок(Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку(0), ВозвращатьКакУИД);
КонецФункции
// Функция - Уникальный идентификатор набора строк. Ключ записи.
//
// Параметры:
// СписокUUID - Массив Из Строка - Массив с произвольными строками
// ВозвращатьКакУИД - Булево - определяет, возвращать ли результат как УникальныйИдентификатор. Если Ложь - возвращается строкой
//
// Возвращаемое значение:
// Строка, УникальныйИдентификатор - Ключ записи для некоторого набора строк
//
Функция УникальныйИдентификаторНабораСтрок(СписокСтрок, ВозвращатьКакУИД = Ложь) Экспорт
СписокДляСортировки = Новый СписокЗначений;
СписокДляСортировки.ЗагрузитьЗначения(СписокСтрок);
СписокДляСортировки.СортироватьПоЗначению(НаправлениеСортировки.Возр);
СписокСтрок = СписокДляСортировки.ВыгрузитьЗначения();
СтрокаОбщая = СтрСоединить(СписокСтрок, ",");
Хеширование = Новый ХешированиеДанных(ХешФункция.SHA1);
Хеширование.Добавить(СтрокаОбщая);
ДвоичныеДанные = Хеширование.ХешСумма;
Хеш = НРег(ПолучитьHexСтрокуИзДвоичныхДанных(ДвоичныеДанные));
// Преобразуем хеш в массив байтов (берем первые 16 байтов)
МассивБайтов = Новый Массив;
Сч = 1;
Пока Сч < 32 Цикл
Байт = Сред(Хеш, Сч, 2);
МассивБайтов.Добавить(Байт);
Сч = Сч + 2;
КонецЦикла;
// Версия UUID 5
МассивБайтов[6] = СтрШаблон("5%1", Прав(МассивБайтов[6], 1));
// Вариант RFC 4122
ДесятичноеЧисло = ЧислоИзШестнадцатеричнойСтроки(СтрШаблон("0x%1", МассивБайтов[8]));
БезДвухБитов = ПобитовоеИ(ДесятичноеЧисло, 63); // обнуляем старшие 2 бита, 63 = 0011 1111
ИтоговыйБайт = ПобитовоеИли(БезДвухБитов, 128); // записываем в старшие 2 бита 10, 128 = 1000 000
СимволыHEX = "0123456789abcdef";
СтаршийРазряд = Сред(СимволыHEX, Цел(ИтоговыйБайт / 16) + 1, 1);
МладшийРазряд = Сред(СимволыHEX, (ИтоговыйБайт % 16) + 1, 1);
МассивБайтов[8] = СтаршийРазряд + МладшийРазряд;
UUIDБезРазделителей = СтрСоединить(МассивБайтов, "");
ИтоговыйUUID = СтрШаблон("%1-%2-%3-%4-%5",
Сред(UUIDБезРазделителей, 1, 8),
Сред(UUIDБезРазделителей, 9, 4),
Сред(UUIDБезРазделителей, 13, 4),
Сред(UUIDБезРазделителей, 17, 4),
Сред(UUIDБезРазделителей, 20, 12));
Если Не СтроковыеФункцииКлиентСервер.ЭтоУникальныйИдентификатор(ИтоговыйUUID) Тогда
ВызватьИсключение "Не удалось получить уникальный идентификатор из входных данных. Строка " + ИтоговыйUUID + " не отвечает требованиям УИД";
КонецЕсли;
Если ВозвращатьКакУИД Тогда
ИтоговыйUUID = Новый УникальныйИдентификатор(ИтоговыйUUID);
КонецЕсли;
Возврат ИтоговыйUUID;
КонецФункции
Единственный БСП-шный вызов:
Если Не СтроковыеФункцииКлиентСервер.ЭтоУникальныйИдентификатор(ИтоговыйUUID) Тогда
ВызватьИсключение "Не удалось получить уникальный идентификатор из входных данных. Строка " + ИтоговыйUUID + " не отвечает требованиям УИД";
КонецЕсли;
Поэтому если эта проверка не нужна, то можно вырезать.