При разработке интерфейсов на платформе 1С:Предприятие 8.3 часто возникает задача отобразить в форме списка не только основные реквизиты объекта, но и данные из его табличных частей. Типичный пример из УТ 11 или ERP — вывод контактной информации (номера телефона или адреса электронной почты) в списке контрагентов или контактных лиц. На первый взгляд задача кажется простой, но при использовании динамических списков разработчики часто сталкиваются с проблемой дублирования строк или невозможностью настроить корректную связь. В этой статье мы подробно разберем, как правильно решить эту задачу, избежав типичных ошибок.
Рассмотрим стандартную ситуацию: мы хотим добавить колонку "Телефон" в динамический список. Если мы просто добавим в запрос динамического списка ЛЕВОЕ СОЕДИНЕНИЕ с табличной частью КонтактнаяИнформация, то получим крайне неприятный эффект. Если у одного контактного лица указано три телефона (рабочий, мобильный, домашний), то в списке это лицо продублируется трижды. Это происходит потому, что динамический список работает по принципам реляционных баз данных: одна запись в присоединенной таблице рождает одну строку в результате запроса.
Для решения этой проблемы существуют два основных подхода: программное заполнение данных через специальное событие списка и использование нескольких соединений с фильтрацией по виду. Проанализируем каждый из них.
Это наиболее гибкий метод, который позволяет избежать дублирования строк и дает возможность выводить данные именно так, как нам нужно (например, объединять несколько телефонов в одну строку через запятую). Суть метода заключается в том, что мы не пытаемся получить данные сразу в основном запросе списка, а "дотягиваем" их программно, когда система отрисовывает конкретную порцию строк на экране пользователя.
Рассмотрим пошагово реализацию этого метода:
ВЫБРАТЬ ..., NULL КАК ТелефонПредставление ИЗ .... После этого в элементах формы появится новая колонка.ПриПолученииДанныхНаСервере.Посмотрим на пример кода, который эффективно решает задачу:
&НаСервере
Процедура СписокПриПолученииДанныхНаСервере(ИмяЭлемента, Настройки, Строки)
// Получаем массив ссылок на объекты, которые сейчас отображаются в списке
МассивСсылок = Строки.ПолучитьКлючи();
// Создаем запрос для получения контактной информации только по этим объектам
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| КИ.Ссылка КАК Ссылка,
| КИ.Представление КАК Представление
|ИЗ
| Справочник.КонтактныеЛицаПартнеров.КонтактнаяИнформация КАК КИ
|ГДЕ
| КИ.Ссылка В(&МассивСсылок)
| И КИ.Вид.Наименование ПОДОБНО ""%Телефон%""";
Запрос.УстановитьПараметр("МассивСсылок", МассивСсылок);
Выборка = Запрос.Выполнить().Выбрать();
// Заполняем данные в строках списка
Пока Выборка.Следующий() Цикл
ТекущаяСтрока = Строки[Выборка.Ссылка];
ТекущаяСтрока.Данные["ТелефонПредставление"] = Выборка.Представление;
КонецЦикла;
КонецПроцедуры
Важный нюанс: Обратите внимание на использование Строки.ПолучитьКлючи(). Это критически важно для производительности. Запрос выполняется не для всей базы, а только для тех 20-40 записей, которые пользователь видит на экране в данный момент. Это делает работу списка молниеносной даже при миллионах записей в справочнике.
Если вам критически важно иметь возможность сортировки или поиска по полю телефона, метод с событием ПриПолученииДанныхНаСервере не подойдет, так как данные в нем существуют только "визуально". В этом случае придется модифицировать текст запроса самого динамического списка.
Чтобы избежать дублей, мы должны присоединить табличную часть столько раз, сколько видов информации мы хотим видеть, и в каждом соединении жестко ограничить вид контактной информации. Выясним, как это выглядит на практике:
ВЫБРАТЬ
КонтактныеЛица.Ссылка,
КонтактныеЛица.Наименование,
ТаблицаТелефоны.Представление КАК Телефон,
ТаблицаПочта.Представление КАК ЭлектроннаяПочта
ИЗ
Справочник.КонтактныеЛицаПартнеров КАК КонтактныеЛица
ЛЕВОЕ СОЕДИНЕНИЕ Справочник.КонтактныеЛицаПартнеров.КонтактнаяИнформация КАК ТаблицаТелефоны
ПО КонтактныеЛица.Ссылка = ТаблицаТелефоны.Ссылка
И ТаблицаТелефоны.Вид = &ВидТелефон
ЛЕВОЕ СОЕДИНЕНИЕ Справочник.КонтактныеЛицаПартнеров.КонтактнаяИнформация КАК ТаблицаПочта
ПО КонтактныеЛица.Ссылка = ТаблицаПочта.Ссылка
И ТаблицаПочта.Вид = &ВидПочта
В этом случае параметры &ВидТелефон и &ВидПочта нужно установить программно при создании формы, используя метод Список.Параметры.УстановитьЗначениеПараметра(). Этот метод гарантирует, что на каждую строку справочника придется максимум одна строка из табличной части (при условии, что у объекта только один телефон конкретного вида).
Проанализируем ситуацию в современных конфигурациях на базе БСП (Бизнес-стандарт подсистем). В УТ 11, ERP и КА контактная информация часто хранится не только в табличных частях, но и в специальных регистрах сведений (например, КонтактнаяИнформация). Работа через регистр сведений в динамическом списке более предпочтительна с точки зрения скорости доступа к данным.
Также стоит помнить о поле Представление. В табличных частях контактной информации поле Представление содержит уже сформированную строку (например, "+7 (999) 000-00-00"). Всегда используйте именно его для вывода в списки, чтобы не нагружать сервер вычислениями по сборке номера из кода страны, города и добавочного номера.
Резюмируем:
ПриПолученииДанныхНаСервере.ЛЕВОЕ СОЕДИНЕНИЕ в тексте запроса с обязательной фильтрацией по ВидКИ.ПриПолученииДанныхНаСервере текущими ключами строк (Строки.ПолучитьКлючи()), чтобы не "повесить" систему медленными запросами.Применяя эти подходы, мы сможем создавать удобные и информативные списки, сохраняя при этом высокую производительность системы.