Что было:
А. База на платформе 8.3.5.1248 обычные формы.
Б. В базе список справочника "Номенклатура" иерархический.
Что нужно:
Подсчет количества элементов в списке справочника "Номенклатура", при изменении отбора.
Решение:
Для решения нам понадобится:
1. В список справочника "Номенклатура" добавить колонку "КоличествоЭлементов" (вы можете назвать её как вам нужно, но не забудьте потом изменить код).
2. Для элемента формы "Список" определить процедуру:
Процедура СписокПриПолученииДанных(Элемент, ОформленияСтрок)
Для Каждого ОформлениеСтрок Из ОформленияСтрок Цикл
Если ОформлениеСтрок.ДанныеСтроки.ЭтоГруппа Тогда
ОформлениеСтрок.Ячейки.КоличествоЭлементов.Значение = ПолучитьКоличествоЭлементов(ОформлениеСтрок.ДанныеСтроки.Ссылка);
Иначе
ОформлениеСтрок.Ячейки.КоличествоЭлементов.Значение = 1;
КонецЕсли;
КонецЦикла;
КонецПроцедуры
3. Осталось посчитать в функции количество самих элементов:
Функция ПолучитьКоличествоЭлементов(ГруппаНоменклатуры)
КоличествоЭлементов = 0;
Построитель = Новый ПостроительЗапроса;
Построитель.Текст = "ВЫБРАТЬ
| *
|ИЗ
| Справочник.Номенклатура КАК Номенклатура
|ГДЕ
| Номенклатура.ЭтоГруппа = ЛОЖЬ
| И Номенклатура.Родитель = &ГруппаНоменклатуры";
Построитель.Параметры.Вставить("ГруппаНоменклатуры",ГруппаНоменклатуры);
Построитель.ЗаполнитьНастройки();
//Установка отбора в построителе
Для Каждого ЭлементОтбора Из Список.Отбор Цикл
Если ЭлементОтбора.Использование Тогда
Если Построитель.Отбор.Найти(ЭлементОтбора.ПутьКДанным) = Неопределено Тогда
ЭлементОтбораВПостроителе = Построитель.Отбор.Добавить(ЭлементОтбора.ПутьКДанным);
ЭлементОтбораВПостроителе.ВидСравнения = ЭлементОтбора.ВидСравнения;
ЭлементОтбораВПостроителе.Значение = ЭлементОтбора.Значение;
ЭлементОтбораВПостроителе.ЗначениеС = ЭлементОтбора.ЗначениеС;
ЭлементОтбораВПостроителе.ЗначениеПо = ЭлементОтбора.ЗначениеПо;
ЭлементОтбораВПостроителе.Использование = Истина;
КонецЕсли
КонецЕсли;
КонецЦикла;
//Получение результатов
Построитель.Выполнить();
Выборка = Построитель.Результат.Выбрать();
КоличествоЭлементов = Выборка.Количество();
Возврат КоличествоЭлементов;
КонецФункции
Результат:
Код написали. Отбор работает. Результат производительности при открытии одно из папок: 0,360265.
Казалось бы, отлично, задача решена! Но это решение можно оптимизировать!
И сейчас я покажу, как улучшить результат в разы!
Решение2:
1. Без изменений.
2. Допишем условие, чтобы код работал только тогда, когда колонка "КоличествоЭлементов" видима:
Процедура СписокПриПолученииДанных(Элемент, ОформленияСтрок)
ВидимостьКоличествоЭлементов = ЭлементыФормы.Список.Колонки.КоличествоЭлементов.Видимость;
Для Каждого ОформлениеСтрок Из ОформленияСтрок Цикл
Если ВидимостьКоличествоЭлементов Тогда
Если ОформлениеСтрок.ДанныеСтроки.ЭтоГруппа Тогда
ОформлениеСтрок.Ячейки.КоличествоЭлементов.Значение = ПолучитьКоличествоЭлементов(ОформлениеСтрок.ДанныеСтроки.Ссылка);
Иначе
ОформлениеСтрок.Ячейки.КоличествоЭлементов.Значение = 1;
КонецЕсли;
КонецЕсли;
КонецЦикла;
КонецПроцедуры
3. Оптимизируем запрос, уменьшив количество обращений к базе (обратите внимание на условие в запросе и путь к данным для отбора):
Функция ПолучитьКоличествоЭлементов(ГруппаНоменклатуры)
КоличествоЭлементов = 0;
Построитель = Новый ПостроительЗапроса;
Построитель.Текст = "ВЫБРАТЬ
| КОЛИЧЕСТВО(*) КАК Количество
|ИЗ
| Справочник.Номенклатура КАК Номенклатура
|ГДЕ
| Номенклатура.ЭтоГруппа = ЛОЖЬ
| И Номенклатура.Родитель = &ГруппаНоменклатуры
|{ГДЕ
| Номенклатура.Ссылка.*}";
Построитель.Параметры.Вставить("ГруппаНоменклатуры",ГруппаНоменклатуры);
Построитель.ЗаполнитьНастройки();
//Установка отбора в построителе
Для Каждого ЭлементОтбора Из Список.Отбор Цикл
Если ЭлементОтбора.Использование Тогда
Если Построитель.Отбор.Найти(ЭлементОтбора.ПутьКДанным) = Неопределено Тогда
ЭлементОтбораВПостроителе = Построитель.Отбор.Добавить("Ссылка." + ЭлементОтбора.ПутьКДанным);
ЭлементОтбораВПостроителе.ВидСравнения = ЭлементОтбора.ВидСравнения;
ЭлементОтбораВПостроителе.Значение = ЭлементОтбора.Значение;
ЭлементОтбораВПостроителе.ЗначениеС = ЭлементОтбора.ЗначениеС;
ЭлементОтбораВПостроителе.ЗначениеПо = ЭлементОтбора.ЗначениеПо;
ЭлементОтбораВПостроителе.Использование = Истина;
КонецЕсли
КонецЕсли;
КонецЦикла;
//Получение результатов
Построитель.Выполнить();
Выборка = Построитель.Результат.Выбрать();
Пока Выборка.Следующий() Цикл
КоличествоЭлементов = Выборка.Количество;
КонецЦикла;
Возврат КоличествоЭлементов;
КонецФункции
Результат2:
Теперь наш код стал оптимальнее. Отбор работает, как и должен. А вот результат производительности: 0,113300.
Нам удалось улучшить результат в разы, и это отлично!
Задача решена на 100%!
Благодарности:
Исходный код был подсмотрен тут. В оптимизации решения помог Молодов Алексей!