Поиск в динамическом списке.

Главная Заметки из Зазеркалья

21.04.2014 Получение данных динамического списка

Реализовано в версии 8.3.6.1977.

Мы реализовали возможность простого и удобного получения данных, отображаемых с помощью динамического списка.

Данные динамического списка могут понадобиться вам для того, чтобы распечатать их в нестандартном, «специфическом» виде. Или для того, чтобы выполнить с ними те или иные действия. Например, послать письмо всем контрагентам, которых вы отобрали в списке по некоторым признакам.

Кроме этого существует целый ряд задач, в которых пользователь, помимо списка элементов, хочет видеть ещё и итоговые данные, связанные с этим списком. Например, отобрав товары некоторой товарной группы и некоторого поставщика, он тут же хочет увидеть общее количество таких товаров в базе.

Динамический список сам по себе не может предоставить вам такую информацию. Задача динамического списка - обеспечить быстрый просмотр больших объёмов данных. Поэтому он считывает данные порциями, требуемыми для отображения на одном-двух экранах. И «ничего не знает», например, об общем количестве данных, которые ему предстоит считать.

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

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

Теперь эта задача решается просто. У таблицы динамического списка появились два новых метода:

  • ПолучитьИсполняемуюСхемуКомпоновкиДанных() ;
  • ПолучитьИсполняемыеНастройкиКомпоновкиДанных() .

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

В результате вы получите структуру (или отчет), содержащую колонки и строки, выводимые в таблицу динамического списка.

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

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

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

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

При создании система по умолчанию добавит на форму табличное поле с типом «Динамический список».

Зайдем в его свойства и посмотрим, что там.

В первую очередь нас интересует флажок «Произвольный запрос». Он-то и откроет нам все преимущества динамического списка. У нас появится возможность написать собственный запрос, причем с параметрами. Устанавливаем флажок и нажимаем ссылку «Открыть»:

Откроется окно с уже готовым кодом на . Пока что там просто перечислены все поля справочника «Номенклатура».

Получите 267 видеоуроков по 1С бесплатно:

Как видим, имеется кнопка вызова « » и флажок, который дает возможность динамически изменять содержимое списка. То есть когда другой пользователь меняет что-то в справочнике, в нашем списке это тоже изменится. Кроме того, имеется закладка «Настройки», но ее мы коснемся позже.

Собственный запрос в динамическом списке

Сначала создадим нужный нам запрос с остатками и ценами. Примерно так:

Закладка «Настройки»

И вот теперь самое вкусное! Переходим на закладку «Настройки». И сразу видим, что на первой вкладке мы можем делать любые отборы по любому полю в запросе:

Программная установка параметров запроса в динамическом списке 1С 8.3

Не забываем, что в запросе у нас присутствуют два параметра: «Период» и «Тип цен». Мы должны передать их в запрос, иначе будет ошибка.

Пропишем эти параметры в параметрах формы, а в модуле формы добавим следующие строки:

&НаСервере Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка) Список. Параметры. УстановитьЗначениеПараметра("Период" , Параметры. Дата) ; Список. Параметры. УстановитьЗначениеПараметра("ТипЦен" , Параметры. ТипЦен) ; КонецПроцедуры

Платформа 1С:Предприятие 8.2 может работать с множеством записей в таблице базы данных динамическим способом, то есть считывать данные порциями. Ранее в статьях мы рассматривали механизм динамических списков и методы оптимизации работы с ними.

Сегодня мы решим нестандартную задачу для динамических списков. Нам нужно будет подсчитать итог по реквизиту документа "Сумма" и вывести его в подвале списка. Аналогично подсчитать среднее значение для поля "Рейтинг" и также вывести в подвале динамического списка. Подсчет итоговых полей должен учитывать отбор, установленный пользователем в настройках списка документов.

Вся сложность заключается в том, что динамический список не получает сразу все записи, а получает их порциями. Соответственно, мы не можем сразу получить итог по всем документам, соответствующим текущему отбору. Каким же образом посчитать итог?

Реализация

И так, перейдем к решению задачи. Начнем с изменении формы, далее опишем алгоритм получения итоговых значений.

Форма и интерфейс

Для начала подготовим форму документа для отображения итоговых полей. Для этого добавим два строковых реквизита формы "Рейтинг" и "Сумма".

В данные реквизиты будут записываться итоговые значения по документам.

Для отображения значений реквизитов в подвале динамического списка необходимо включить соответствующую опцию связанного элемента формы списка (см. следующий скриншот).

Теперь нужно определиться по какому событию будет проиходить обновление итогов в подвале списка. Для удобства разработки добавим команду "Обновить" и соответствующий ей элемент формы на командную панель. При выполнении этой команды будет происходить обновление итогов.

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

Алгоритм

Осталась самая проблематичная часть - нужно получить значения итогов. Поступим следующим образом: будем формировать запрос к базе данных на получение значений итоговых полей в соответствии с отбором, установленным в динамическом списке. Стоит учитывать, что в отборе может стоять сложное условие из групп.

Примечание: настройки динамических списков (см. скриншот выше) основываются на механизмах системы компоновки данных (СКД) . Соответственно, работать с ними можно аналогичным образом (программное добавление, изменение, чтение и прочее).

Этапы формирования запроса для получения итогов следующие:

1. Получаем исходный запрос динамического списка.

Как мы видим, запрос выбирает все реквизиты документа. Для небольшого усложнения добавил собственное поле "УровеньРейтинга", формируемое конструкцией "ВЫБОР".

2. Формируем текст условий запроса (секция "ГДЕ") и подставляем в исходный запрос.

К полученному исходному тексту запроса нам необходимо добавить условия в соответствии с настроенным отбором динамического списка.

Процедура, в зависимости от типа переданного элемента отбора (группа или элемент отбора) формирует соответствующий текст условия. Все условия в группе обрамляются скобками, входящие группу также обрамляются круглыми скобками. Условия между выражениями зависят от вышестоящей группы (между верхними в иерархии элементами ставится условие "И").

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

Еще одной интересной, на мой взгляд, функцией является "ПолучитьТекстПоляПоПредставлению". Нужна она для того, чтобы подставлять в условия запроса поля, которые формируются выражениями языка запроса. Выше в исходный запрос мной было добавлено поле "УровеньРейтинга". Если пользователь будет использовать его в отборе, то в условие запроса нужно подставлять полностью все выражение. Данная функция получает текст поля из запроса по его представлению. Для таких сложных полей она вернет полностью весь текст выражения.

Подробнее алгоритм смотрите в тестовой конфигурации, приложенной к статье. Ниже приведу скриншот настроек отбора и сформированных для них условий запроса.

Сформированный текст условий присоединяется к исходному запросу динамического списка. Результат запроса помещается во временную таблицу.

3. Первый запрос помещаем во временную таблицу и выполняем группировку по итоговым полям с необходимыми агрегатными функциями.

Напомню, что нам нужно получить среднее значение по полю "Рейтинг" и общую сумму по полю "Сумма". Запрос с учетом отборов мы уже сформировали, осталось произвести подсчет итоговых значений. Делается это следующим запросом:

После выполнения запроса обрабатываем полученный результат, возвращаем его на клиент и записывает в реквизиты формы, которые мы создали ранее. В конечном счете мы получили отображение итогов в подвале динамического списка (см. первый скриншот к статье).

Оптимальность решения

Вообще, данный подход может отрицательно повлиять на производительность. Например, если программа будет подсчитывать итог без установленного отбора в динамическом списке, то количество выбираемых записей может быть огромным (например, за несколько лет). В итоге каждое обновление итогов может продолжаться десятки (!!!) секунд. Поэтому имеет смысл подсчитывать итоги только если был установлен отбор. Данное условия поставил в тестовой конфигурации.

Плюс ко всему, подсчет итогов, запрос мы можем сделать только на стороне сервера. Поэтому нужно серьезно подойти к обращению на сервер, так как процедура обновления итогов может выполняться очень часто. Представьте себе журнал чеков ККМ в торговой организации, где за минуту может быть введено до 5 чеков, а в час до 300 чеков. Каждый раз после записи документа будет вызываться обновление итогов. Поэтому разумно было бы сократить передаваемый трафик за счет использования внеконтекстных процедур.

На следующем скриншоте представлен программный код вызова внеконтекстной серверной функции, возвращающей итоги.

Первым параметром передаем отбор динамического списка, вторым структуру типа "ИмяПоляОтбора ТипЗначенияПоляОтбора". Обратите внимание, что первый параметр в функции получается как самостоятельное значение. Не могу сказать точно по какой причине, но если передавать отбор как ссылку, то платформа выдает ошибку о том, что нельзя изменить отбор. Ошибку удалось обойти только подобным образом.->

Примечание: использование внеконтекстных процедур позволяет сократить размер передаваемого трафика в разы, так как данные формы на сервер не передаются, в отличии от контекстных серверных процедур (директива "&НаСервере").

Вывод

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

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

Тем не менее, описанный в статье способ имеет место при решении задач.

Файлы для загрузки:

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

Для демонстрации возможностей динамического списка создадим внешнюю обработку, добавим основную форму. На форму добавим новый реквизит с типом «Динамический список». Зайдем в его свойства и посмотрим, что там.
Нас интересует свойство «Произвольный запрос». Его включение продемонстрирует нам все возможности динамического списка. Мы сможем написать запрос, используя практически все возможности языка запросов системы 1С: Предприятие. Устанавливаем флажок и нажимаем ссылку «Открыть»:

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


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

Если мы попробуем запустить нашу обработку в таком виде, то получим ошибку:


Для ее устранения необходимо установить значение параметру «Период». Для этого можно воспользоваться методом «УстановитьЗначениеПараметра» коллекции «Параметры» динамического списка. Метод принимает два параметра:
. «Параметр» - Тип: Строка; ПараметрКомпоновкиДанных. Имя параметра или параметр компоновки данных, значение которого нужно установить;
. «Значение» - Тип: Произвольный. Значение, которое нужно установить.
Может быть вызван в обработчике «ПриСозданииНаСервере» формы:

У вас есть вопрос, нужна помощь консультанта?


Предоставим пользователю возможность изменять период получения остатков. Для этого добавим реквизит и связанный с ним элемент формы «Дата»:


В обработчике «ПриИзменении» элемента формы «Дата» вызовем метод «УстановитьЗначениеПараметра», передав в качестве значения значение связанного реквизита. Аналогичным образом изменим процедуру «ПриСозданииНаСервере» формы. Так как метод доступен на клиенте, вызов сервера не потребуется:


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




Предположим, что пользователи хотят видеть либо текущие остатки, либо планируемые поступления. Рассмотрим один из вариантов реализации. Добавим реквизит формы булевого типа и связанный с ним переключатель:


При изменении значения переключателя будем менять текст запроса. Для этого воспользуемся обработчиком события «ПриИзменении» элемента формы «ОтображатьКоличествоКПоступлению». Нам необходимо изменить свойство «ТекстЗапроса» динамического списка в зависимости от значения реквизита. Так как данное свойство недоступно на клиенте необходим вызов серверной процедуры:


Результат внесенных изменений: