При работе с классическими конфигурациями 1С на обычных формах часто возникает задача: вывести в список документов или журнал информацию, которой нет в реквизитах самого журнала. Например, нужно отобразить текущий статус оплаты, артикул номенклатуры из состава табличной части или ответственного менеджера из связанного документа. Поскольку прямой связи в метаданных нет, данные приходится получать с помощью запроса «на лету».
В этой статье мы подробно разберем, как правильно реализовать этот механизм, избежав типичных ошибок новичков и проблем с производительностью системы.
Для отрисовки данных в табличном поле (списке) в обычных формах существуют два основных события: ПриВыводеСтроки и ПриПолученииДанных. Проанализируем их различия, чтобы понять, какой метод эффективнее.
Событие ПриВыводеСтроки вызывается системой в тот момент, когда конкретная строка списка отрисовывается на экране. Если мы попытаемся выполнить запрос к базе данных внутри этого обработчика, то при прокрутке списка (скроллинге) система будет выполнять по одному запросу для каждой строки. Если на экране 30 строк — это 30 отдельных обращений к СУБД. Это создает колоссальную нагрузку и приводит к «тормозам» интерфейса.
Событие ПриПолученииДанных работает иначе. Оно вызывается один раз для всей порции строк, которые система планирует отобразить. В параметрах этого события мы получаем коллекцию ОформленияСтрок, которая содержит информацию обо всех видимых строках сразу. Это позволяет нам применить пакетную обработку данных: собрать все ссылки, выполнить один запрос и распределить результат по ячейкам.
Рассмотрим пошаговый алгоритм реализации вывода данных с помощью одного запроса. Допустим, нам нужно вывести «Контрагента» в журнал, где этого поля нет в метаданных.
Шаг 1. Создание колонки. Вы можете добавить колонку (Графу) в конфигураторе в объект «Журнал документов», либо добавить колонку программно в самом табличном поле на форме. Важно: свойство Данные у этой колонки должно оставаться пустым.
Шаг 2. Реализация обработчика. Проанализируем пример кода, который объединяет ссылки в массив и получает данные одним махом:
Процедура ЖурналДокументовСписокПриПолученииДанных(Элемент, ОформленияСтрок)
// 1. Собираем ссылки всех видимых строк в массив
МассивСсылок = Новый Массив;
Для Каждого Оформление Из ОформленияСтрок Цикл
МассивСсылок.Добавить(Оформление.ДанныеСтроки.Ссылка);
КонецЦикла;
// 2. Выполняем один запрос к базе данных
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ЗаказПокупателя.Ссылка КАК Ссылка,
| ЗаказПокупателя.Контрагент КАК Контрагент
|ИЗ
| Документ.ЗаказПокупателя КАК ЗаказПокупателя
|ГДЕ
| ЗаказПокупателя.Ссылка В(&МассивСсылок)";
Запрос.УстановитьПараметр("МассивСсылок", МассивСсылок);
ТаблицаДанных = Запрос.Выполнить().Выгрузить();
// 3. Используем Соответствие для быстрого поиска данных по ссылке
СоответствиеДанных = Новый Соответствие;
Для Каждого СтрокаТЗ Из ТаблицаДанных Цикл
СоответствиеДанных.Вставить(СтрокаТЗ.Ссылка, СтрокаТЗ.Контрагент);
КонецЦикла;
// 4. Распределяем данные по ячейкам оформления
Для Каждого Оформление Из ОформленияСтрок Цикл
СсылкаНаДокумент = Оформление.ДанныеСтроки.Ссылка;
ЗначениеПоля = СоответствиеДанных.Получить(СсылкаНаДокумент);
Если ЗначениеПоля <> Неопределено Тогда
// Устанавливаем текст в нашу виртуальную колонку "Контрагент"
Оформление.Ячейки.Контрагент.УстановитьТекст(Строка(ЗначениеПоля));
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Этот подход гарантирует высокую скорость работы даже при больших объемах данных, так как количество запросов к базе минимизировано.
Если данные уже есть в объекте (например, это свойство самой ссылки) и их не нужно получать сложным запросом, можно использовать более простой обработчик ПриВыводеСтроки. Однако помните, что обращение через точку от ссылки (например, ОформлениеСтроки.ДанныеСтроки.Ссылка.Контрагент) — это тоже неявный запрос к базе данных.
Разберем типичную ошибку. Многие пытаются записать данные напрямую в ДанныеСтроки, но система выдает ошибку "Поле объекта не обнаружено" или "Реквизит не доступен для записи". Это происходит потому, что ДанныеСтроки отражают состояние данных в базе, а не визуальное представление.
Правильный способ — работа через коллекцию Ячейки объекта ОформлениеСтроки:
Процедура ЖурналДокументовСписокПриВыводеСтроки(Элемент, ОформлениеСтроки, ДанныеСтроки)
// Правильная установка значения через ОформлениеСтроки
ОформлениеСтроки.Ячейки.Контрагент.УстановитьТекст(ДанныеСтроки.Ссылка.Контрагент);
// Можно также менять цвет фона или шрифт
Если ДанныеСтроки.Проведен Тогда
ОформлениеСтроки.Ячейки.Контрагент.ЦветТекста = ЦветаСтиля.ЦветДистанционнойРаботы;
КонецЕсли;
КонецПроцедуры
При использовании программного вывода колонок следует учитывать несколько критически важных моментов:
ПриПолученииДанных или ПриВыводеСтроки, невозможно осуществлять стандартную сортировку или поиск. Платформа не видит этих данных в физической таблице базы данных. Если пользователю жизненно необходима сортировка по этому полю, его придется добавлять как реальную «Графу» в метаданные журнала и заполнять при записи документов.Соответствие для кэширования результатов. При повторном вызове события для тех же строк данные можно будет брать из памяти, а не из базы.ПриОткрытии формы:
НоваяКолонка = ЭлементыФормы.ЖурналДокументовСписок.Колонки.Вставить(0, "ВиртуальнаяКолонка");
НоваяКолонка.Имя = "СтатусДокумента";
НоваяКолонка.ТекстШапки = "Статус";
НоваяКолонка.Ширина = 15;
После этого к ячейке с именем "СтатусДокумента" можно обращаться в обработчиках оформления строк, как мы рассматривали выше.
Таким образом, мы выяснили, что для эффективной работы интерфейса в обычных формах 1С следует отдавать предпочтение методу ПриПолученииДанных с использованием пакетных запросов. Это позволяет гибко расширять функциональность журналов и списков без существенной потери производительности.