Как заполнить табличную часть в 1С на основании реквизита

Программист 1С v8.3 (Управляемые формы)
← На главную

В разработке на платформе «1С:Предприятие 8» очень часто возникает задача автоматического заполнения табличной части документа при изменении какого-либо реквизита на форме. Например, при выборе подразделения или группы услуг нам необходимо мгновенно заполнить спецификацию документа подходящими элементами.

Рассмотрим практический кейс: в документе ОценкаЗначимостиРиска на управляемой форме расположен реквизит Подразделение, ссылающийся на справочник Услуги. В этом же документе есть табличная часть Оценка с реквизитом Риск (тип СправочникСсылка.Услуги). Наша задача — при выборе подразделения автоматически найти все конечные элементы (услуги), входящие в это подразделение, и заполнить ими табличную часть.

Анализ типичных ошибок начинающих разработчиков

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

  1. Запрос внутри цикла обхода табличной части. Написание конструкции Для Каждого Строка Из Объект.Оценка Цикл перед выполнением запроса является грубой ошибкой. Если табличная часть изначально пуста, цикл просто не выполнится ни разу. Если же табличная часть заполнена, выполнение запроса внутри цикла создаст колоссальную и неоправданную нагрузку на СУБД.
  2. Выбор наименования вместо ссылки в запросе. Попытка выбрать в запросе Услуги.Наименование вместо Услуги.Ссылка приводит к тому, что система пытается записать строковое значение в реквизит с типом «СправочникСсылка». Это вызывает ошибку несоответствия типов.
  3. Простое сопоставление родителя без учета иерархии. Условие Услуги.Родитель = &Подразделение выберет только элементы, находящиеся строго на один уровень ниже выбранной папки. Если справочник имеет сложную структуру со вложенными группами, элементы из подгрупп не попадут в результат. Для обхода всей ветки дерева необходимо использовать оператор В ИЕРАРХИИ.
  4. Игнорирование групп справочника. Если не наложить фильтр Услуги.ЭтоГруппа = Ложь, в табличную часть наряду с элементами запишутся и сами папки (группы), что обычно недопустимо по бизнес-логике.

Решение проблемы: Базовый рабочий вариант

Разберем по шагам классический способ решения данной задачи. Нам понадобятся обработчик события изменения реквизита на клиенте и сопутствующий серверный контекстный вызов.

Начнем с клиентской процедуры, которая реагирует на изменение подразделения на форме:


&НаКлиенте
Процедура ПодразделениеПриИзменении(Элемент)
	ПодразделениеПриИзмененииНаСервере();
КонецПроцедуры

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


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

Оптимальный вариант с использованием метода Загрузить()

Посмотрим на ситуацию с точки зрения производительности и стандартов разработки «1С:Предприятия». Построчный обход выборки запроса с вызовом метода Добавить() работает медленно, если справочник содержит сотни или тысячи элементов.

Платформа 1С предоставляет отличную возможность быстрой вставки данных с помощью метода Загрузить(). Если имя колонки в результате запроса совпадает с именем реквизита табличной части (в нашем примере это Риск), мы можем выгрузить результат запроса в Таблицу Значений и одной строчкой загрузить ее в табличную часть.

Также добавим в запрос крайне важное условие — исключение помеченных на удаление элементов справочника Услуги, чтобы в документ попадали только актуальные данные.

Проанализируем оптимизированный код:


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

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

← На главную