Запрос к таблице значений

05 июня 2013

Пример задачи

У нас есть номенклатура, находящаяся в группе "Запрещенная номенклатура", которую нужно запретить пользователям использовать в документе "Заказ поставщику" в табличной части "Товары". При этом стоит учитывать тот факт, что позиция номенклатуры может находиться не в самой группе "Запрещенная номенклатура", а в подчиненных ей группах. В этом случае запрет также должен действовать. Плюс ко всему нужно добавить проверку заполнения внутреннего заказа. 

Проверку следует выполнять перед записью документа в базу данных, если текущий режим записи "проведение".

Реализация

Перейдем в модуль объекта документа, в событие "ПередЗаписью". Здесь нам и нужно реализовать проверку корректности заполнения. Поскольку запись в этом событии мы имеем лишь объект документа еще не помещенный в базу данных, то выполнить запрос непосредственно к таблице документа "Товары" у нас не получится.

Почему выполнять проверку нужно именно запросом? Дело в том, что при использовании объектной модели доступа к данным подобная проверка обойдется достаточно не затратной по ресурсам для серверной машины. Если мы будем выполнять конструкции типа:

Если СтрокаТаблицы.Номенклатура.Родитель.Родитель.Родитель = ЗапрещеннаяГруппа Тогда
	// Действия 
КонецЕсли;

то время выполнения события "ПередЗаписью" может резко увеличится.

Наиболее оптимальный вариант решения - это использования запроса для проверки корректности заполнения, ведь в нем мы можем использовать конструкцию

"В ИЕРАРХИИ ()"

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

 	Если РежимЗаписи = РежимЗаписиДокумента.Проведение Тогда
		// Выгружаем таб. документа в таблицу значений с нужными колонками
		ТабТовары = Товары.Выгрузить(, "НомерСтроки, Номенклатура, Заказ");
		Запрос = Новый Запрос;
		// Передаем таб. значений в запрос в качестве параметра
		Запрос.УстановитьПараметр("ТабДок", ТабТовары);
		// Устанавливаем запрещенную группу номенклатуры
		Запрос.УстановитьПараметр("ЗапрещеннаяГруппа", 
			Справочники.Номенклатура.НайтиПоНаименованию("Запрещенная номенклатура", Истина));
		Запрос.Текст = "ВЫБРАТЬ
		|	Т.НомерСтроки,
		|	Т.Номенклатура,
		|	ВЫБОР
		|		КОГДА Т.Заказ = ЗНАЧЕНИЕ(Документ.ЗаказНаПроизводство.ПустаяСсылка)
		|				ИЛИ Т.Заказ = ЗНАЧЕНИЕ(Документ.ЗаказПокупателя.ПустаяСсылка)
		|				ИЛИ Т.Заказ = ЗНАЧЕНИЕ(Документ.ВнутреннийЗаказ.ПустаяСсылка)
		|				ИЛИ Т.Заказ = НЕОПРЕДЕЛЕНО
		|			ТОГДА ИСТИНА
		|		ИНАЧЕ ЛОЖЬ
		|	КОНЕЦ КАК ЗаказНеЗаполнен
		|ПОМЕСТИТЬ Таб
		|ИЗ
		// Переданную таблицу подставляем в секцию "ИЗ" в качестве параметра
		|	&ТабДок КАК Т 
		|ГДЕ
		|	(Т.Номенклатура В ИЕРАРХИИ (&ЗапрещеннаяГруппа)
		|			ИЛИ ВЫБОР
		|				КОГДА Т.Заказ = ЗНАЧЕНИЕ(Документ.ЗаказНаПроизводство.ПустаяСсылка)
		|						ИЛИ Т.Заказ = ЗНАЧЕНИЕ(Документ.ЗаказПокупателя.ПустаяСсылка)
		|						ИЛИ Т.Заказ = ЗНАЧЕНИЕ(Документ.ВнутреннийЗаказ.ПустаяСсылка)
		|						ИЛИ Т.Заказ = Неопределено
		|					ТОГДА ИСТИНА
		|				ИНАЧЕ ЛОЖЬ
		|			КОНЕЦ)
		|;
		|
		|////////////////////////////////////////////////////////////////////////////////
		|ВЫБРАТЬ
		|	Таб.Номенклатура,
		|	Таб.НомерСтроки,
		|	Таб.ЗаказНеЗаполнен
		|ИЗ
		|	Таб КАК Таб";
		Выборка = Запрос.Выполнить().Выбрать();
		// Обрабатываем результат
		Пока Выборка.Следующий() Цикл
			ОбщегоНазначения.СообщитьОбОшибке("В строке " + Выборка.НомерСтроки + 
			" используется запрещенная номенклатура " +
			"""" + Выборка.Номенклатура + """" 
			+ ?(Выборка.ЗаказНеЗаполнен, ", а также не заполнен заказ!", ""), Отказ);
		КонецЦикла;
	КонецЕсли;

В запрос таблица значений передается в качестве параметра. Если открыть такой запрос в конструкторе, то подобная таблица будет определена как "Описание временной таблицы" и выглядеть следующим образом:

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

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

Вывод

Задача была решена. Пример сработанной проверки перед записью документа:

Конечно, приведенный пример достаточно простой. Задачу можно было решить переместив проверку в событие "ПриЗаписи", тогда мы бы обошлись простым запросам к базе данных без передачи в запрос таблицы значений. О том, чтобы судить о правильности использования описанного способа нужно знать конкретные условия задачи.


comments powered by Disqus