Как наиболее быстро найти подчиненные документы для раскраски списка в 1С

Программист 1С v8.3 (Обычные формы) IT и автоматизация бизнеса
← На главную

Переход с платформы 7.7 на 8.х часто ставит перед разработчиками задачи, которые раньше решались «малой кровью», но требуют иного подхода в новой архитектуре. Одна из таких задач — динамическая раскраска строк списка документов в зависимости от наличия подчиненных документов определенного типа, причем с учетом любой глубины вложения. Разберем, как реализовать этот механизм максимально эффективно, не жертвуя производительностью интерфейса.

Анализ проблемы и выбор события для раскраски

В обычных формах (платформа 8.2 и 8.3 в режиме совместимости) раскраска строк традиционно выполняется в событиях списка ПриВыводеСтроки или ПриПолученииДанных. Проанализируем разницу: событие ПриВыводеСтроки вызывается для каждой отрисовываемой строки, что удобно для простых вычислений. Однако, если нам нужно выполнять сложные запросы к базе данных, использование этого события приведет к катастрофическому падению скорости скроллинга. Поэтому для массовых операций лучше использовать ПриПолученииДанных, которое позволяет обработать массив строк одним пакетом.

Решение 1: Использование критериев отбора

Критерии отбора — это мощный штатный механизм 1С для поиска связей между объектами. В типовых конфигурациях (например, УТ 10.3 или БП 2.0) часто существует предопределенный критерий СвязанныеДокументы.

Рассмотрим пример кода, который проверяет наличие подчиненных документов через этот механизм:


// Пример проверки наличия подчиненных документов
МассивСсылок = КритерииОтбора.СвязанныеДокументы.Найти(ТекущийДокумент.Ссылка);
ЕстьПодчиненные = (МассивСсылок.Количество() > 0);

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

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

Решение 2: Использование функций типовых конфигураций

Если вы работаете в конфигурации «Бухгалтерия предприятия 2.0», можно воспользоваться готовым программным интерфейсом. Разберем использование функции из общего модуля ПолныеПрава.


// Получение списка всех подчиненных документов в БП 2.0
// мКэшПраваДоступаКМетаданным - предварительно инициализированный кэш
СписокПодчиненных = ПолныеПрава.ПолучитьСписокПодчиненныхДокументов(ТекущийДокумент, мКэшПраваДоступаКМетаданным);

Этот метод удобен тем, что он уже оптимизирован разработчиками фирмы «1С» под конкретную конфигурацию и учитывает права доступа пользователя к метаданным.

Решение 3: Реализация раскраски в событии ПриПолученииДанных

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

Выясним, как это выглядит на практике:


Процедура ДокументСписокПриПолученииДанных(Элемент, ОформленияСтрок)
    
    // 1. Собираем ссылки всех документов, которые сейчас видны на экране
    МассивСсылок = Новый Массив;
    Для Каждого Оформление Из ОформленияСтрок Цикл
        МассивСсылок.Добавить(Оформление.ДанныеСтроки.Ссылка);
    КонецЦикла;
    
    // 2. Выполняем запрос к критерию отбора или таблице связей
    // Здесь мы определяем, у каких документов есть подчиненный тип "ПланПроизводства"
    Запрос = Новый Запрос;
    Запрос.Текст = 
    "ВЫБРАТЬ РАЗЛИЧНЫЕ
    |    СвязанныеДокументы.Ссылка КАК Основание
    |ИЗ
    |    КритерийОтбора.СвязанныеДокументы(&МассивСсылок) КАК СвязанныеДокументы
    |ГДЕ
    |    ТИПЗНАЧЕНИЯ(СвязанныеДокументы.Ссылка) = ТИП(Документ.ПланПроизводства)";
    
    Запрос.УстановитьПараметр("МассивСсылок", МассивСсылок);
    ТаблицаСвязей = Запрос.Выполнить().Выгрузить();
    ТаблицаСвязей.Индексировать("Основание");
    
    // 3. Раскрашиваем строки
    Для Каждого Оформление Из ОформленияСтрок Цикл
        СсылкаНаДок = Оформление.ДанныеСтроки.Ссылка;
        Если ТаблицаСвязей.Найти(СсылкаНаДок, "Основание") <> Неопределено Тогда
            Оформление.ЦветФона = Новый Цвет(200, 255, 200); // Светло-зеленый
        КонецЕсли;
    КонецЦикла;

КонецПроцедуры

Решение 4: Проблема глубокой вложенности (Архитектурный подход)

Поиск на любую глубину вхождения в реальном времени — это ресурсозатратная операция. Если в вашей базе цепочки документов могут достигать 5–10 уровней, а документов в день создаются сотни, стандартные запросы к критериям отбора не обеспечат мгновенного отклика.

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

  1. При проведении любого документа в этот регистр записываются пары: ГоловнойДокументТекущийДокумент.
  2. При записи система рекурсивно поднимается вверх до самого первого основания и прописывает связи для всех «предков» текущего документа.
  3. В результате, чтобы узнать, есть ли у «Заказа» подчиненный «План производства» на любой глубине, достаточно одного простейшего запроса к индексу регистра по двум полям.

Особенности работы в файловом режиме

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

Резюме

Для быстрой раскраски списка документов по типу подчиненных:

  1. Используйте Критерии отбора для поиска прямых связей.
  2. Обязательно делайте проверку в событии ПриПолученииДанных, обрабатывая список документов одним запросом.
  3. Для поиска на неограниченную глубину рассмотрите создание индексированного регистра сведений, который будет хранить готовую структуру подчиненности.
  4. Если работаете в управляемых формах, перенесите логику в Динамический список, используя левое соединение (LEFT JOIN) в тексте запроса — это позволит платформе самой оптимизировать выборку данных.
← На главную