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