Есть такой вопрос:
Мне необходимо сделать уникальный в пределах справочника идентификатор из 16 цифр.
Пользовался 2-умя разными способами, но ни один не привел к успеху. Через какое то время появляются дубли. Не пойму как.
Способ 1:
Функция СоздатьЧисловойГУИД(Спр) Экспорт
ГУИД = "";
Строка = "0123456789";
ГЧС = Новый ГенераторСлучайныхЧисел();
Пока СтрДлина(ГУИД)<=16 Цикл
ГУИД = ГУИД + Сред(Строка, ГЧС.СлучайноеЧисло(0,СтрДлина(Строка)), 1);
КонецЦикла;
Если ПоискЧисловогоГУИДа(Строка(ГУИД), Спр) = Ложь Тогда
Возврат ГУИД;
Иначе
СоздатьЧисловойГУИД(Спр);
КонецЕсли;
КонецФункции
Показать
Способ 2:
Функция СоздатьЧисловойГУИД(Спр) Экспорт
Попытка
ScrptCtrl = новый COMОбъект("MSScriptControl.ScriptControl");
ScrptCtrl.Language="javascript";
Код = "function randomInteger(min, max){
|var rand = min - 0.5 + Math.random() * (max - min + 1);
|rand = Math.round(rand);
|return rand;
|}";
ScrptCtrl.AddCode(Код);
//СтрокаВыполнения = "randomInteger(" + мин + "," + СтрЗаменить(макс, Символы.НПП, "") + ")";
СтрокаВыполнения = "randomInteger(0, 9999999999999999)";
Ответ = ScrptCtrl.Eval(СтрокаВыполнения);
УИДСтрокой = СтрЗаменить(Ответ, Символы.НПП, "");
Если СтрДлина(УИДСтрокой) < 16 Тогда
Для сч = 0 По 16 - СтрДлина(УИДСтрокой) - 1 Цикл
УИДСтрокой = "0" + УИДСтрокой;
КонецЦикла;
КонецЕсли;
Если ПоискЧисловогоГУИДа(УИДСтрокой, Спр) = Ложь Тогда
Возврат УИДСтрокой;
Иначе
СоздатьЧисловойГУИД(Спр);
КонецЕсли;
Исключение
СоздатьЧисловойГУИД(Спр);
КонецПопытки;
КонецФункции
Показать
Функция поиска:
Функция ПоискЧисловогоГУИДа(ГУИД, Спр) Экспорт
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ "+Спр+".УИД
|ИЗ
| Справочник."+Спр+" КАК "+Спр+"
|ГДЕ
| "+Спр+".УИД = &УИД";
Запрос.УстановитьПараметр("УИД", ГУИД);
РезультатЗапроса = Запрос.Выполнить();
ВыборкаДетальныеЗаписи = РезультатЗапроса.Выбрать();
Если (ВыборкаДетальныеЗаписи.Количество() > 1) Тогда
Возврат Истина;
ИначеЕсли (ВыборкаДетальныеЗаписи.Количество() = 0) Тогда
Возврат Ложь;
Иначе
Возврат Истина;
КонецЕсли;
КонецФункции
Показать
Есть кое-какие вещи излишние, например, ряд условий. На текущий момент все находится в тесте, на боевой базе не используется, но даже в тестовой базе умудряются появиться дубли.
(1) чем код справочника не устраивает ? Это ведь и есть по своей сути уникальный идентификатор, ну сделайте его 16 значным и все.
А генератор случайных чисел, - это немного не то...Случайный - не значит уникальный.
как вариант можно самодельную функцию присобачить, с привязкой ко времени.
генератором двигаете знаков 8-10, и добавляете количество , например минут с определенной точки отсчета...н-р, начало этого года.
В году 525600минут в одном году, лет на 10 запас сделать и все
(6) Вот самое интересное, что уникальности алгоритм позволяет добиться так как после генерации происходит проверка на существование в базе. Вот тут проблема и кроется. Проходит неделя две и появляется дубль в базе. Запрос проверяет наличие каждый раз, но все же получается что платформа в запросе даёт нулевой результат, следовательно создаётся ещё один ИД, который в базе есть. Только как я не понимаю?
13.
user618912_redgad
1315.08.17 07:15 Сейчас в теме
Создаешь новый справочник. Тип номера - числовой. Длина номера - 16.
В твой справочник добавляешь реквизит с типом созданного справочника.
Ну и при записи создаешь новый элемент справочника и записываешь ссылку на него в добавленный реквизит.
Ещё вариант:
Создаешь регистр сведений, куда записываешь кучу заранее сгенерированных идентификаторов, а потом случайным образом из них выбираешь любой и удаляешь его из регистра.
Нагенерировать следующую порцию будет сложнее, зависит от того, как генерировалось изначально. Если были взяты числа подряд с начала, то надо будет просто помнить последнее число, и продолжить генерировать начиная с него. Иначе придется собирать числа, которые уже были использованы и удалены из регистра.
Чтобы сгенерить случайное число, берите все имеющиеся значения запросом, помещайте их в таблицу значений, сортируйте. Далее, если нужен новый ГУИД, Берите последнее значение и добавляйте единицу.
Если нужно прямо генерировать, то сделайте следущим образом:
1. Таблицу значений нужно создавать с двумя колонками (ГУИД и КоличествоКопий. В запросе для "КоличествоКопий" ставите единицу - 1);
1. Создаете генерацию кода.
2. Добавляете в таблицу значений
3. Сворачиваете таблицу по ГУИД с суммированием колонки "КоличествоКопий".
4. Поиск в колонке КоличествоКопий = 2
5. Если неопределено, то вы создали уникальный код.
6. Если есть дубль, то генерировать новый не нужно. Делаете следующее:
а) Начинаете перебор коллекции (таблицы значений) с места, где был зафиксирован дубль
б) Прибавляете единицу к ГУИДу и сравниваете с текущим значением в итерации
в) До тех пор, пока не ГУИД не станет уникальным (если значений тьма, можно придумать функцию по поиску "пробела" между группой цифр).
Не знаю, я бы не заморачивался со всякими проверками...
смещение даты использовать да и все.
Текущая дата, в минутах, или секаундах - это по факту счетчик, который нам даст уникальность..ну и генератором генерим код. Потом соединяем, и получаем уникальное число, даже если генератор выдал повторяющийся код.
например,
5000001 минута+генератор выдал 2
5000002 минута генератор выдал 38
5000010 минута генератор выдал снова 2
но по факту число все равно уникальное.
500000102, 500000238,500001002
главное чтобы в одну и ту же минуту, у нас генератор не выдал одинаковое число..но тут вероятность много ниже, чем в разрезе недель месяцев или лет.
Хотя и с этим можно бороться..добавлять в конец числа текущую секунду
но когда получает значение 63 638 542 123 123
то приходится делать
СтрЗаменить(УИД, Символы.НПП, "");
А после добавлять нули в начале, так как длина строки не 16 символов
Проверка все равно нужна, так как в базе уже присутсвуют идентификаторы других элементов
УИД должен быть строковый.
создайте вспомогательный независимый регистр с измерением - ГУИД. При создании элемента справочника добавляйте запись в регистр, при удалении - не удаляйте.
Вообще странно, что рандом на 16-значном числе выдает дубли. Значит, кривой какой-то алгоритм рандома.
Функция СоздатьЧисловойГУИД(Спр) Экспорт
УИД = Формат(ТекущаяУниверсальнаяДатаВМиллисекундах(), "ЧЦ=16; ЧВН=; ЧГ=0");
Если Не Справочники[Спр].НайтиПоРеквизиту("УИД", УИД) = Справочники[Спр].ПустаяСсылка() Тогда
СоздатьЧисловойГУИД(Спр);
Иначе
Возврат УИД;
КонецЕсли;
КонецФункции