Альтернативный способ передачи произвольных параметров между процедурами/сеансами/фоновыми заданиями

Программирование - Практика программирования

В статье описан возможно не новый, но полезный способ передачи параметров между сеансами/процедурами и функциями/фоновыми заданиями

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

Казалось бы, задача для опытного (да и не очень опытного) 1С-ника простая, нужно всего лишь добавить реквизит, вывести его на форму, найти процедуру заполнения и доработать её.

Однако, в моем случае процедура заполнения документа вызывалась через типовой механизм "Длительные операции" или по-простому через механизм "Фоновых заданий", т.е. по нажатию на кнопку "Заполнить", программа заполняла структуру параметров и запускала фоновое задание из модуля менеджера документа с этими параметрами. Далее, вызывались нужные процедуры по заполнению таблиц документа. Однако, в эти процедуры передавалась не вся структура параметров (куда я мог поместить и свой в том числе), а лишь некоторые из них. Плюс к этому одним вызовом нужной процедуры дело не ограничивалось, до того, как параметры доходили до нужной процедуры заполнения они преодолевали тернистый путь из последовательного вызова 7-8 типовых процедур.

Иными словами, для такой "простейшей" задачи нужно было перелопачивать программный код (прописывать во все вызовы процедур наш дополнительный параметр), что потом бы неизбежно привело к проблемам с обновлениями.

Решено было создать простой регистр сведений, который был назван "ДополнительныеПараметрыПроцедурИФункций":

В результате чего алгоритм решения вышеописанной задачи свелся к следующему:

  1. Перед заполнением установить значение нужного нам параметра, записав его значение в регистр сведений
  2. В процедуре заполнения прочитать значение параметра из регистра 
  3. Непосредственно доработать саму процедуру с учетом нашего параметра

Почему я для данного случая не использовал:

  1. Константы - не подходят для данного случая, так как параметры могут быть различными (у константы должно быть уникальное имя) и не постоянными (зависят, например, от значения реквизита конкретного документа)
  2. Параметры сеанса - данные параметры уникальны только в разрезе конкретного сеанса. Т.е. на примере выше, когда "поднимается" фоновое задание у него уже "свои" значения параметров сеанса

Процедуры чтения/записи значения параметров:

Процедура УстановитьЗначениеДопПараметраПроцедурИФункций(ИмяПараметра, ЗначениеПараметра) Экспорт
	
	НаборЗаписей = РегистрыСведений.ДополнительныеПараметрыПроцедурИФункций.СоздатьНаборЗаписей();
	НаборЗаписей.Отбор.ИмяПараметра.Установить(ИмяПараметра);
	НаборЗаписей.Прочитать();
	НаборЗаписей.Очистить();
	
	НоваяЗапись = НаборЗаписей.Добавить();
	НоваяЗапись.ИмяПараметра = ИмяПараметра;
	НоваяЗапись.ЗначениеПараметра = ЗначениеПараметра;
	
	НаборЗаписей.Записать();
	
КонецПроцедуры

Функция ВернутьЗначениеДопПараметраПроцедурИФункций(ИмяПараметра) Экспорт
	
	ЗначениеПараметра = Неопределено;
	
	НаборЗаписей = РегистрыСведений.ДополнительныеПараметрыПроцедурИФункций.СоздатьНаборЗаписей();
	НаборЗаписей.Отбор.ИмяПараметра.Установить(ИмяПараметра);
	НаборЗаписей.Прочитать();
	
	Для каждого стр из НаборЗаписей Цикл 
		ЗначениеПараметра = стр.ЗначениеПараметра;	
	КонецЦикла;
		
	Возврат ЗначениеПараметра;
	
КонецФункции

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

В приложении к публикации находится простейшая конфигурация, демонстрирующая описанный выше механизм.

Скачать файлы

Наименование Файл Версия Размер
Конфигурация-пример "Дополнительные параметры процедур и функций"
.cf 11,12Kb
08.09.17
0
.cf 11,12Kb Скачать

См. также

Комментарии
1. Вячеслав Голев (Goleff74) 21.08.17 18:50 Сейчас в теме
Процедура УстановитьЗначениеДопПараметраПроцедурИФункций(ИмяПараметра, ЗначениеПараметра) Экспорт
	
	НаборЗаписей = РегистрыСведений.ДополнительныеПараметрыПроцедурИФункций.СоздатьНаборЗаписей();
	НаборЗаписей.Отбор.ИмяПараметра.Установить(ИмяПараметра);
	
	НоваяЗапись = НаборЗаписей.Добавить();
	НоваяЗапись.ИмяПараметра = ИмяПараметра;
	НоваяЗапись.ЗначениеПараметра = ЗначениеПараметра;
	
	НаборЗаписей.Записать();
	
КонецПроцедуры
Показать


Так, пожалуй, красивее будет :)
4. Антон Мартынов (Skin123) 4 22.08.17 09:30 Сейчас в теме
(1). Да, точно красивее:) Спасибо!
2. PerlAmutor IC (PerlAmutor) 7 22.08.17 09:13 Сейчас в теме
Я подобную задачу решал иначе. В БСП есть справочник ДополнительныеОтчетыИОбработки, в каждой обработке можно хранить любые собственные настройки. Соответственно сначала туда записываются параметры, а потом туда же возвращается результат.
5. Антон Мартынов (Skin123) 4 22.08.17 09:36 Сейчас в теме
3. Влад Влад (surikateg) 22.08.17 09:26 Сейчас в теме
Чем плохо СохранитьЗначение(<Имя>, <Значение>) , ВосстановитьЗначение(<Имя>) ? Нет привязки к постоянно изменяющемуся бсп.
6. Игорь Колодин (KilloN) 27 22.08.17 09:50 Сейчас в теме
(3) СохранитьЗначение(<Имя>, <Значение>) , ВосстановитьЗначение(<Имя>) только для толстого клиента.
Лучше использовать ХранилищеОбщихНастроек.Сохранить, Загрузить, Удалить
7. PerlAmutor IC (PerlAmutor) 7 22.08.17 10:03 Сейчас в теме
(6) Пока не пробовал. В качестве минуса наверное можно выделить то, что эти настройки засоряют базу, т.к. при удалении обработки данные там остаются.
8. Игорь Колодин (KilloN) 27 22.08.17 10:11 Сейчас в теме
(7) Да все верно, поэтому нужно вызывать Удалить, или сразу после загрузки, или перед завершением сеанса через функцию ХранилищеОбщихНастроек.ПолучитьСписок(...) очищаем все настройки
12. Антон Мартынов (Skin123) 4 22.08.17 12:44 Сейчас в теме
(8), с хранилищем общих настроек хорошая идея, но они же вроде сохраняются для определенного пользователя? В таком случае, как узнать в фоновом задании настройки какого пользователя читать?
9. Альтаир (Altair777) 639 22.08.17 12:23 Сейчас в теме
Это однопользовательский вариант? Так имя параметра быстрее всего одинаковое для документов одного вида, то коллизии будут возникать с вероятностью чуть менее, чем полностью :)
klinval; sergathome; +2 Ответить
10. Антон Мартынов (Skin123) 4 22.08.17 12:36 Сейчас в теме
(9) Хм, а ведь и правда, в случае, если два пользователя решат одновременно заполнить два разных документа, то коллизия неизбежна. По идее тут нужно еще одно измерение создавать, которое будет отвечать за уникальность значения данного параметра. Подумаю на эту тему, спасибо.
11. Альтаир (Altair777) 639 22.08.17 12:38 Сейчас в теме
(10) достаточно ссылки на документ (?)
13. Антон Мартынов (Skin123) 4 22.08.17 12:49 Сейчас в теме
(11) В общем случае ссылки на документ будет достаточно, ну или как вариант уникального идентификатора, чтобы не привязываться к типу объекта. Однако, в моем случае в процедуре, в которую нужно было передать дополнительный параметр не было ссылки на заполняемый объект, поэтому тут и могут возникнуть сложности в определении значения параметра
18. Вячеслав Голев (Goleff74) 22.08.17 15:58 Сейчас в теме
(13)
Почему проблемы?
Ключ = Строка(Новый УникальныйИдентификатор)

Параметр по этому ключу в РС. И фоновое задание запускать с этим ключом.
15. Игорь Колодин (KilloN) 27 22.08.17 14:35 Сейчас в теме
16. Игорь Колодин (KilloN) 27 22.08.17 14:36 Сейчас в теме
(9)
Это однопользовательский вариант? Так имя параметра быстрее всего одинаковое для документов одного вида, то коллизии будут возникать с вероятностью чуть менее, чем полностью :)


Не будут, тк. хранилище работает, если не указывать конкретного пользователя, для каждого пользователяотдельно!
17. Альтаир (Altair777) 639 22.08.17 15:28 Сейчас в теме
(16) а разве в публикации говорилось о хранилище?!
Не морочьте людям голову
14. Сергей Любезнов (sergathome) 22.08.17 13:08 Сейчас в теме
В общем случае метод годится только для случая, когда им пользуется только один сеанс. То есть не годится даже для регламентных заданий ;)) ИД сеанса нужно в измерения добавлять, как минимум. И передавать этот ИД в фоновое задание стандартным способом. Выигрыш только в том, что можно одним параметром передать сразу много, но что мешает передать структуру сразу ?
Вобсчем поржал. Спасибо.
19. Валерий М (VmvLer) 22.08.17 16:13 Сейчас в теме
Относительно фоновых заданий хранилище имеет только обратную связь, т.е.

при запуске фонового задания в него можно передать адрес хранилища и после завершения фонового задания в точке его
запуска получить значения из хранилища.

Прямая связь не работает, т.е. поместить в хранилище значение, передать в фоновое адрес и в задании получить значение по этому адресу невозможно.

Именно поэтому возникают задачи как в (0)

Я считаю, что с броским названием тс перегнул, ибо
создать регистр хранения в конфигурации - это банальное решение в лоб не претендующее на рациональную идею и альтернативу. это костыль
20. Вячеслав Голев (Goleff74) 22.08.17 16:39 Сейчас в теме
Ну, можно поизвращаться.

На клиентском компутере:

1. Получаем новый УИД.
2. Блокируем по нему исключительно запись в РС.
3. Запускаем фоновое задание, в которое передаем-таки этот уид (только в функцию самого задания).
4. В бесконечном цикле (можно с паузой) опрашиваем фоновое задание на предмет сообщений пользователю.
5. Как только появляется сообщение в РС фигачим по номеру в этом собщении необходимый параметр и снимаем блокировку с записи РС из п.2.

В функции ФЗ:
1. Получаем номер сеанса.
2. Создаем сообщение пользователю, в которое добавляем этот номер сеанса.
3. Делаем запрос к РС по УИДу преданному в качестве параметра ФЗ.
4. Ждем на блокировке...
5. Выполняем свой код. В функции, где нужен параметр с клиента обращаемся в РС по НомерСеансаИнформационнойБазы().
6. Профит

PS Ну, и не забываем, где надо, транзакции всунуть, чтоб блокировка отработала.
PPS Но лучше, каеш, параметр протолкнуть по функциям :)
21. Валерий М (VmvLer) 22.08.17 17:32 Сейчас в теме
чтобы не изобретать велосипед советую использовать БСП

ДлительныеОперации.ЗапуститьВыполнениеВФоне()
Оставьте свое сообщение