Почему динамический список 1С завершает работу при выводе даты документа-основания?

Программист 1С v8.3 (Управляемые формы)
← На главную

Разработчики 1С часто сталкиваются с ситуацией, когда стандартный динамический список документов необходимо расширить данными из связанных объектов. Казалось бы, задача тривиальная: достаточно изменить запрос, добавив ЛЕВОЕ СОЕДИНЕНИЕ (LEFT JOIN). Однако на практике это может привести к внезапному закрытию клиентского приложения («вылету») без объяснения причин, особенно при прокрутке списка. Разберем подробно, почему это происходит и как правильно реализовать подобную задачу.

Анализ проблемы и исходного запроса

Рассмотрим ситуацию: у нас есть документ «Заявление», в котором указан документ-основание «Реестр». Нам нужно вывести в список «Заявлений» номер и дату этого самого «Реестра». Типичный запрос в динамическом списке выглядит следующим образом:


ВЫБРАТЬ
    Заявление.Ссылка КАК Ссылка,
    Заявление.Номер КАК Номер,
    Заявление.Дата КАК Дата,
    Заявление.Основание КАК Реестр,
    Реестр.НомерВходящий КАК РеестрНомерВходящий,
    Реестр.ДатаВходящий КАК РеестрДатаВходящий
ИЗ
    Документ.Заявление КАК Заявление
        ЛЕВОЕ СОЕДИНЕНИЕ Документ.Реестр КАК Реестр
        ПО Заявление.Основание = Реестр.Ссылка

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

Причина 1: Особенности динамического считывания и NULL-значения

Динамический список с установленной Основной таблицей работает не так, как обычный запрос в консоли. Платформа считывает данные порциями (обычно по 20–50 записей), динамически достраивая SQL-запросы при каждом движении колесика мыши.

Когда мы используем ЛЕВОЕ СОЕДИНЕНИЕ, возможна ситуация, когда для конкретного «Заявления» не указано «Основание». В этом случае поля РеестрНомерВходящий и РеестрДатаВходящий будут содержать значение NULL.

Для типа Дата в 1С это критично. В момент отрисовки строки графическая оболочка пытается преобразовать NULL в формат даты. Если в этот же момент срабатывает механизм динамического дозаполнения данных или условное оформление, может произойти конфликт в памяти (Access Violation), приводящий к «падению» клиента. Строковые значения менее чувствительны к этому, так как NULL часто интерпретируется просто как пустая строка.

Причина 2: Сортировка по полям присоединенной таблицы

Проанализируем настройки самого элемента формы «Список». Если в списке включена возможность сортировки пользователем или установлена сортировка по умолчанию по полю РеестрДатаВходящий, нагрузка на СУБД и механизм построения запроса платформой возрастает в разы.

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

Решение 1: Безопасная обработка через ЕСТЬNULL

Первое, что мы должны сделать — гарантировать, что в колонках даты и номера никогда не будет значения NULL. Для этого перепишем запрос, используя функцию ЕСТЬNULL. Это обеспечит типизацию данных на уровне сервера.


ВЫБРАТЬ
    Заявление.Ссылка КАК Ссылка,
    Заявление.Номер КАК Номер,
    Заявление.Дата КАК Дата,
    Заявление.Основание КАК Реестр,
    ЕСТЬNULL(Реестр.НомерВходящий, "") КАК РеестрНомерВходящий,
    ЕСТЬNULL(Реестр.ДатаВходящий, ДАТАВРЕМЯ(1, 1, 1)) КАК РеестрДатаВходящий
ИЗ
    Документ.Заявление КАК Заявление
        ЛЕВОЕ СОЕДИНЕНИЕ Документ.Реестр КАК Реестр
        ПО Заявление.Основание = Реестр.Ссылка

Теперь система всегда будет получать либо реальную дату, либо пустую дату 1С (01.01.0001), что исключает ошибки визуализации при отрисовке пустых ячеек.

Решение 2: Использование регистра «Данные первичных документов»

Рассмотрим более архитектурно правильный подход. В типовых конфигурациях 1С (ERP, КА, УТ 11) существует специальный регистр сведений ДанныеПервичныхДокументов. Он предназначен именно для того, чтобы быстро получать номера и даты любых документов без необходимости делать тяжелые соединения с таблицами самих документов.

Посмотрим на преимущества этого метода:

  1. Производительность: Мы соединяемся с одной узкой таблицей регистра, а не с метаданными конкретного вида документа.
  2. Стабильность: Данные в регистре уже денормализованы и проиндексированы.
  3. Универсальность: Если поле «Основание» имеет составной тип (может быть и Реестром, и Поступлением), нам не придется делать 10 левых соединений для каждого типа.

Решение 3: Программный вывод через «ПриПолученииДанныхНаСервере»

Если вылетов не удается избежать даже с ЕСТЬNULL, проанализируем альтернативный способ — событие ПриПолученииДанныхНаСервере. В этом случае мы убираем соединение из основного запроса динамического списка, оставляя только легкую выборку из одной таблицы.

Разберем алгоритм действий:

  1. В запросе динамического списка оставляем только ссылку на основание.
  2. В модуле формы создаем обработчик события СписокПриПолученииДанныхНаСервере.
  3. В этом обработчике получаем массив ссылок на основания для тех строк, которые реально отображены на экране (обычно это 30-40 строк).
  4. Одним запросом получаем нужные даты и номера.
  5. Заполняем данные в коллекции ОформлениеСтроки.

Этот метод полностью исключает влияние «тяжелых» соединений на работу динамического считывания списка, так как получение данных происходит точечно и только для видимой области экрана.

Дополнительные рекомендации

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

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

← На главную