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

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    30788    dimanich70    83    

152

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

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

1 стартмани

18.03.2024    5001    6    John_d    11    

57

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

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

12.02.2024    34548    atdonya    28    

62

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

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

30.11.2023    6603    ke.92@mail.ru    17    

66

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

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

28.08.2023    18174    YA_418728146    8    

172

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

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

2 стартмани

22.08.2023    4852    79    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    19886    191    sapervodichka    113    

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

Функция ХешСтроки(Алгоритм, Строка)
	
	Хеш = Новый ХешированиеДанных(Алгоритм);
	Хеш.Добавить(Строка);	
	Возврат СтрЗаменить(Строка(Хеш.ХешСумма), " ", "");
				    	
КонецФункции
Показать
poor_developer; +1 Ответить
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));
	
	Возврат Новый УникальныйИдентификатор(СтрСоединить(ЧастиУИД, "-"));
	
КонецФункции
Показать
poor_developer; +1 Ответить
6. poor_developer 19 12.03.25 14:12 Сейчас в теме
(5) Прикольно. Я читал, что для детерминированного ключа используют алгоритм формирования UUID v5, а он хеширование входных данных по SHA1 использует
7. Diversus 2334 12.03.25 14:23 Сейчас в теме
(5) На мой взгляд порядок не важен.
Самое главное, чтобы пропустив через эту функцию, возвращался один и тот же GUID.
Грубо говоря: для строки "привет" всегда возвращался GUID "cdaa7bbf-7f19-418d-bda0-c5511417eb6f", ну и для другой строки измененной минимально, другой GUID. То, как формирует GUID 1С в данном случае не важно. Да, это будет не GUID v4/v5, но для своих задач, которые могут понадобиться это точно будет работать.
8. Cyberhawk 135 14.03.25 05:19 Сейчас в теме
Возврат УникальныйИдентификаторНабораСтрок(Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку(0)
Получается, алгоритм оперирует только УИДами (без типов)?

СписокДляСортировки.СортироватьПоЗначению(
Из-за этого будет коллизия, когда в ТЧ будет две каких-нибудь колонки разных типов, но элементы которых имеют попарно одинаковые УИДы (например, Серия1 + Характеристика1 дадут УИД1+УИД2, а Серия2 + Характеристика2 дадут УИД2+УИД1, а ваш алгоритм посчитает это за одинаковый входной набор).
9. poor_developer 19 14.03.25 07:51 Сейчас в теме
(8)
Получается, алгоритм оперирует только УИДами (без типов)?

В итоге все равно крутится все в строках. По сути первый метод для удобства формирования по одной строке ТЧ, чтобы вытянуть УИДЫ по ссылкам и передать в метод УникальныйИдентификаторНабораСтрок(СписокСтрок, ВозвращатьКакУИД = Ложь). Ничто не мешает вызывать этот метод для произвольных строк, а не УИДов

СписокДляСортировки.СортироватьПоЗначению(

На мой взгляд это нужно, чтобы в разных местах не держать в голове порядок т.н. измерений. В одном месте сформирую по значениям Номенклатура+Характеристика+Назначение, в другом "Характеристика+Номенклатура+Назначение" - ключ будет одинаковый.

имеют попарно одинаковые УИДы (например, Серия1 + Характеристика1 дадут УИД1+УИД2, а Серия2 + Характеристика2 дадут УИД2+УИД1


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

В любом случае количество входных данных нужно определять для каждого документа отдельно. Может где-то этот подход вообще не выйдет применить.
10. Cyberhawk 135 14.03.25 08:03 Сейчас в теме
полагаете, что есть вероятность, что УИД характеристики 1 будет равен УИДу серии 2?
Да. При обменах, например, это вообще штатная ситуация, если один объект источника превращается в несколько объектов приемника (например, один документ источника - в три разных вида документов в приемнике).
количество входных данных нужно определять для каждого документа отдельно. Может где-то этот подход вообще не выйдет применить
Если ключ уникальности создавать не только из самих УИДов, но еще и из типов ссылок, то должно получиться гарантированно универсально.
Оставьте свое сообщение