Генерация уникального ключа набора данных

12.03.25

Разработка - Универсальные функции

Детерминированный ключ - это такой ключ, который всегда вычисляется одинаково при одних и тех же входных данных.

Добрый день! 

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

Для чего это нужно программисту 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 + " не отвечает требованиям УИД";
КонецЕсли;

Поэтому если эта проверка не нужна, то можно вырезать.

UUID уникальный идентификатор ключ записи

См. также

Универсальные функции Программист Платформа 1С v8.3 1C:Бухгалтерия Бесплатно (free)

Благодаря этим пяти строчкам можно больше не заморачиваться с загрузкой из внешних файлов. Пользуюсь везде, всегда и постоянно.

21.05.2024    28419    dimanich70    83    

151

Универсальные функции Программист Платформа 1С v8.3 1C:Бухгалтерия Абонемент ($m)

Задача: вставить картинку из буфера обмена на форму средствами платформы 1С.

1 стартмани

18.03.2024    4764    5    John_d    11    

57

Универсальные функции Программист Стажер Платформа 1С v8.3 1C:Бухгалтерия Бесплатно (free)

Пришлось помучиться с GUID-ами немного, решил поделиться опытом, мало ли кому пригодится.

12.02.2024    30410    atdonya    25    

59

Универсальные функции Программист Платформа 1С v8.3 Бесплатно (free)

На заключительных этапах, когда идет отладка или доработка интерфейса, необходимо много раз переоткрыть внешний объект. Вот один из способов автоматизации этого.

30.11.2023    6354    ke.92@mail.ru    17    

66

WEB-интеграция Универсальные функции Механизмы платформы 1С Программист Платформа 1С v8.3 1C:Бухгалтерия Бесплатно (free)

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

28.08.2023    17554    YA_418728146    8    

170

Пакетная печать Печатные формы Адаптация типовых решений Универсальные функции Платформа 1С v8.3 1С:ERP Управление предприятием 2 1С:Управление торговлей 11 1С:Комплексная автоматизация 2.х Россия Абонемент ($m)

Расширение для программ 1С:Управление торговлей, 1С:Комплексная автоматизация, 1С:ERP, которое позволяет распечатывать печатные формы для непроведенных документов. Можно настроить, каким пользователям, какие конкретные формы документов разрешено печатать без проведения документа.

2 стартмани

22.08.2023    4617    76    progmaster    11    

4

Инструментарий разработчика Универсальные функции Платформа 1С v8.3 1C:Бухгалтерия 1С:Розница 2 1С:ERP Управление предприятием 2 1С:Бухгалтерия 3.0 1С:Управление торговлей 11 1С:Комплексная автоматизация 2.х 1С:Зарплата и Управление Персоналом 3.x Абонемент ($m)

Копирует в буфер значения из списков, из ячеек отчетов, таблиц, настроек списков, других отборов и вставляет в выбранную настройку отбора. Работает с Объект не найден. Работает как в одной так и между разными базами 1С. Использует комбинации [Alt+C] Копировать список, [Alt+V] Вставить список. Также для копирования данных используется стандартная [Ctrl+C] (например из открытого xls, mxl, doc и т.п. файла скопировать список наименований)

1 стартмани

13.10.2022    19543    186    sapervodichka    112    

137
Комментарии
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
1. dsdred 3795 12.03.25 13:18 Сейчас в теме
А хеш чем не годится?
Берешь таблицу, стерилизуешь ее в текст и получаешь хеш текста.
Можно и по строкам так сделать.
SerVer1C; +1 Ответить
3. poor_developer 6 12.03.25 13:50 Сейчас в теме
(1) Мы не ищем легких путей) А если серьезно, хотел получать именно УИД, чтобы было какое-то однообразие с типовым, что ли. Во внутреннем потреблении, как пример, идентификатор строки УИДом записывается
4. dsdred 3795 12.03.25 13:52 Сейчас в теме
(3) Ясно. за подвиги плюсик поставлю ))
poor_developer; +1 Ответить
2. Diversus 2332 12.03.25 13:27 Сейчас в теме
В догонку:

// Уникальный идентификатор по произвольной строке.
// 
// Параметры:
//  Строка - Строка - Произвольная строка (можно не УникальныйИдентификатор)
// 
// Возвращаемое значение:
//  УникальныйИдентификатор - Уникальный идентификатор по произвольной строке
Функция УникальныйИдентификаторПоПроизвольнойСтроке(Знач Строка) Экспорт
	
	// BSLLS:MagicNumber-off
	Хеш = НРег(MD5(Строка));
	СтрокаУникальныйИдентификатор = СтрШаблон("%1-%2-%3-%4-%5", 
		Лев(Хеш, 8),
		Сред(Хеш, 9, 4),
		Сред(Хеш, 13, 4),
		Сред(Хеш, 17, 4),
		Прав(Хеш, 12));
	// BSLLS:MagicNumber-on
	
	Возврат Новый УникальныйИдентификатор(СтрокаУникальныйИдентификатор);
	
КонецФункции

// Возвращает хеш-сумму по алгоритму MD5.
// 
// Параметры:
//  Данные - Строка, ДвоичныеДанные - Исходная строка.
// 
// Возвращаемое значение:
//  Строка - Хеш-сумма MD5
Функция MD5(Знач Данные) Экспорт
	
	Возврат ХешСтроки(ХешФункция.MD5, Данные);			    
	
КонецФункции

Функция ХешСтроки(Алгоритм, Строка)
	
	Хеш = Новый ХешированиеДанных(Алгоритм);
	Хеш.Добавить(Строка);	
	Возврат СтрЗаменить(Строка(Хеш.ХешСумма), " ", "");
				    	
КонецФункции
Показать
5. SlavaKron 12.03.25 14:05 Сейчас в теме
(2)
Лев(Хеш, 8),
Сред(Хеш, 9, 4),
Сред(Хеш, 13, 4),
Сред(Хеш, 17, 4),
Прав(Хеш, 12));
По какому принципу формируете УИД из 16-байтового хеша? В 1С, например, другой порядок.
Функция ПолучитьХешКлючаАналитики(ТаблицаЗначенийАналитик) Экспорт
	
	ТаблицаЗначенийАналитик.Сортировать("Аналитика", Новый СравнениеЗначений);
	
	ХешированиеДанных = Новый ХешированиеДанных(ХешФункция.MD5);
	
	Для Каждого Стр Из ТаблицаЗначенийАналитик Цикл
		
		ХешированиеДанных.Добавить(ПолучитьДвоичныеДанныеИзСтроки(XMLСтрока(Стр.Аналитика)));
		ХешированиеДанных.Добавить(ПолучитьДвоичныеДанныеИзСтроки(XMLСтрока(Стр.Значение)));
		
	КонецЦикла;
	
	Стр = СтрЗаменить(ХешированиеДанных.ХешСумма, " ", "");
	ЧастиУИД = Новый Массив;
	ЧастиУИД.Добавить(Прав(Стр, 8));
	ЧастиУИД.Добавить(Сред(Стр, 21, 4));
	ЧастиУИД.Добавить(Сред(Стр, 17, 4));
	ЧастиУИД.Добавить(Лев(Стр, 4));
	ЧастиУИД.Добавить(Сред(Стр, 5, 12));
	
	Возврат Новый УникальныйИдентификатор(СтрСоединить(ЧастиУИД, "-"));
	
КонецФункции
Показать
6. poor_developer 6 12.03.25 14:12 Сейчас в теме
(5) Прикольно. Я читал, что для детерминированного ключа используют алгоритм формирования UUID v5, а он хеширование входных данных по SHA1 использует
7. Diversus 2332 12.03.25 14:23 Сейчас в теме
(5) На мой взгляд порядок не важен.
Самое главное, чтобы пропустив через эту функцию, возвращался один и тот же GUID.
Грубо говоря: для строки "привет" всегда возвращался GUID "cdaa7bbf-7f19-418d-bda0-c5511417eb6f", ну и для другой строки измененной минимально, другой GUID. То, как формирует GUID 1С в данном случае не важно. Да, это будет не GUID v4/v5, но для своих задач, которые могут понадобиться это точно будет работать.
Оставьте свое сообщение