Менеджер обмена данными - популярный и очень своеобразный продукт.
В статье рассматривается решение одной из его проблем - получения нового уникального IDD.
После оптимизации проведения ключевых документов у нас начались блокировки констант.
Переделывать будем вот эту функцию:
Функция ПолучитьНовыйИДД() //Предусматриваем одновременное обращение к константе нескольких пользователей Блокировка=1; Пока Блокировка=1 Цикл Попытка НачатьТранзакцию(); Константа.УникальныйIDD=Константа.УникальныйIDD;//блокируем Блокировка=0;//константа заблокирована не была - можем работать Исключение//константа заблокирована !! ОтменитьТранзакцию(); //Ожидание для возможности работы других пользователей (по совету Олега Яковлева из ЧПТФ "ЮСИ") Стр=ТекущееВремя(); Пока Стр=ТекущееВремя() Цикл КонецЦикла; КонецПопытки; КонецЦикла; //Увеличиваем счетчик в константе на единицу Константа.УникальныйIDD=Число(Константа.УникальныйIDD)+1; Рез=Прав("0000000"+СокрЛП(Константа.IDD),7)+прав("0000000000"+СокрЛП(Константа.УникальныйIDD),10); ЗафиксироватьТранзакцию(); Возврат Рез; КонецФункции
До совета Олега Яковлева она, видимо, вообще не давала жизни пользователям
Итак, приступим...
Будем использовать 1С++.
В глобальном модуле в процедуру ПриначалеРаботыСистемы() добавим следующие строки для создания таблицы и заполнения ее значениями:
//таблица IDD для МОДа ТекстЗапроса = " |if not exists (select name from dbo.sysobjects where name = 'UIDD' and xtype = 'U ') |create table UIDD (idd char(7), uidd numeric(10,0))|"; RecordSet.ВыполнитьИнструкцию(ТекстЗапроса); //начальное заполнение значений таблицы ТекстЗапроса = " |if (select count(*) from UIDD (nolock)) = 0 |insert into UIDD values (:ИДД,:УникальныйИДД) |"; RecordSet.УстановитьТекстовыйПараметр("ИДД",Константа.IDD); RecordSet.УстановитьТекстовыйПараметр("УникальныйИДД",Число(Константа.УникальныйIDD)); RecordSet.ВыполнитьИнструкцию(ТекстЗапроса);
Теперь переделанный текст функции (спасибо за обсуждение на 1cpp.ru коллегам):
Функция ПолучитьНовыйИДД() Экспорт ТекстЗапроса = " |begin tran |select right('0000000' + LTrim(idd), 7) + right('0000000000' + LTrim(str(uidd + 1, 10)),10) |from UIDD (updlock) |update UIDD |set uidd = uidd + 1 |commit tran |"; ТЗ = RecordSet.ВыполнитьИнструкцию(ТекстЗапроса); Возврат ТЗ.ПолучитьЗначение(1,1); КонецФункции
Другой вариант из обсуждения:
//инициализация таблицы ТекстЗапроса = " |if object_id('uidd') is null |create table uidd(uidd numeric(10,0) identity(:УникальныйИДД,1)) |"; RecordSet.УстановитьТекстовыйПараметр("УникальныйИДД", Число(Константа.УникальныйIDD)); RecordSet.ВыполнитьИнструкцию(ТекстЗапроса); //использование Функция ПолучитьНовыйИДД() Экспорт ТекстЗапроса = " |begin tran |insert into uidd default values |select right('0000000000' + LTrim(str(@@identity, 10)),10) |rollback tran |"; ТЗ = RecordSet.ВыполнитьИнструкцию(ТекстЗапроса); Возврат Константа.IDD+ТЗ.ПолучитьЗначение(1,1); КонецФункции
Слово Экспорт добавили не зря.
В обработках конфигурации мы найдем изобилие конструкций с блокировкой константы, которые также нужно переделать.
Пример переделанного кода (оригинальные строки кода разработчиков закоментированы).
Для ы=1 по Метаданные.Справочник() Цикл НачатьТранзакцию(); //Блокировка=1; //Пока Блокировка=1 Цикл // Попытка // НачатьТранзакцию(); // Константа.УникальныйIDD=Константа.УникальныйIDD; //блокируем // Блокировка=0; //константа заблокирована не была - можем работать // Исключение //константа заблокирована !! // ОтменитьТранзакцию(); // //Ожидание для возможности работы других пользователей (по совету Олега Яковлева из ЧПТФ "ЮСИ") // Стр=ТекущееВремя(); // Пока Стр=ТекущееВремя() Цикл // КонецЦикла; // КонецПопытки; //КонецЦикла; КолПрогрессора=КолПрогрессора+10; Прогрессор(КолПрогрессора);//**************** прогрессор Ст=Метаданные.Справочник(ы).Идентификатор; Если (ст<>"ПравилаЗагрузки") и (ст<>"ПравилаВыгрузки") и (ст<>"ПериферийныеБазы") Тогда Спр=СоздатьОбъект("Справочник."+Ст); М_Состояние("Обработка "+Ст); Спр.ВыбратьЭлементы(0); Пока Спр.ПолучитьЭлемент()>0 Цикл Если (Сокрлп(Спр.IDD)="")ИЛИ(ФлНовый=1) Тогда //Константа_УникальныйIDD=Константа_УникальныйIDD+1; //Спр.IDD=Сокрлп(Константа_IDD+прав("0000000000"+Константа_УникальныйIDD,10)); Спр.IDD = ПолучитьНовыйИДД(); Попытка Спр.Записать(); Исключение Сообщить("Ошибка на : "+Спр.Вид()+", владелец "+Спр.Владелец+", элемент="+Спр.ТекущийЭлемент() +", код="+Спр.Код+" . Внимание: найдите данный элемент справочника вручную и измените код !!"); КонецПопытки; КонецЕсли; Если РежимИниц=1 Тогда ПриИзмененииОбъектаМОД(Спр,Спр,'01.01.1976',0);//для периодических реквизитов надо задавать период выгрузки ПриИзмененииОбъектаМОД(Спр,Спр,РабочДата,0);//у нас период равен: 01.01.1976 - рабочая дата КонецЕсли; КонецЦикла; КонецЕсли; //Константа.УникальныйIDD=Строка(Число(Константа_УникальныйIDD)+1); ЗафиксироватьТранзакцию(); КонецЦикла;
Не забывайте о том, что МОД при нахождении неуникальных IDD присваивает уникальные значения УЖЕ СУЩЕСТВУЮЩИМ объектам.
Лично я это пока что закомментировал
Другие статьи по МОДу:
Настройка обмена пакетами МОД по расписанию
Примеры нестандартных настроек правил обмена МОД
Другие статьи по прямым запросам:
Проверка дублей строк с помощью 1С++
Аналог ON DUPLICATE KEY UPDATE в MS SQL
Как использовать УРБД в отличающихся конфигурациях
Примеры решения нестандартных задач на T-SQL в 1С
Как написать прямой запрос в 1С (DBF, 1sqlite)
Онлайн резервирование товаров на складе (online reservation)