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