Как вывести статус «НЕ настроен» для отсутствующих записей в регистре сведений 1С?

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

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

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

Анализ типичных ошибок исходного решения

Для начала проанализируем, почему код автора из первого сообщения темы не работал или работал крайне неэффективно. Типичный ошибочный подход выглядит следующим образом:


// Ошибочный подход чтения всего регистра через набор записей
НаборЗаписей = РегистрыСведений.НастройкаВебСерверов.СоздатьНаборЗаписей;
НаборЗаписей.Прочитать();
ТзРег = НаборЗаписей.Выгрузить();
Для Каждого Регистр Из ТзРег Цикл
    Если НЕ ЗначениеЗаполнено(Регистр.Организация) Тогда
        НовСтрока = ТЗ.Добавить();
        НовСтрока.Организация = Регистр.Организация;
    КонецЕсли;
КонецЦикла;

Давайте выясним причины, по которым данный подход категорически неприменим в реальных задачах:

  1. Избыточное чтение данных из БД. Метод Прочитать() без установки отбора считывает абсолютно все записи из регистра сведений в оперативную память. Если в базе данных будут десятки тысяч записей, это приведет к зависанию формы и перегрузке сервера.
  2. Неверная логика обработки отсутствия данных. Попытка проверить ЗначениеЗаполнено(Регистр.Организация) внутри цикла по существующим записям регистра бессмысленна. Если записи по контрагенту в регистре нет, то цикл по таблице регистра вообще «не узнает» об этом контрагенте. Нам нужно отталкиваться от справочника контрагентов, а не от таблицы регистра.
  3. Попытка записи в базу данных при открытии формы. В некоторых вариантах предлагается принудительно записывать пустые настройки в регистр, если их там нет. Это грубое нарушение паттернов проектирования. Чтение данных (открытие формы для просмотра) ни в коем случае не должно приводить к модификации данных в базе (записи пустых строк).

Разбираемся с механикой ЛЕВОГО соединения и значением NULL

Для решения нашей задачи идеально подходит операция ЛЕВОГО СОЕДИНЕНИЯ (LEFT JOIN) в запросе. Мы берем за основу таблицу справочника Справочник.Контрагенты (левая таблица) и присоединяем к ней виртуальную таблицу среза последних регистра сведений РегистрСведений.НастройкаВебСерверов.СрезПоследних (правая таблица).

При левом соединении СУБД вернет все строки из левой таблицы. Если для какого-то контрагента в правой таблице (регистре сведений) найдется соответствующая запись, то поля регистра заполнятся реальными данными. Если же записи в регистре нет, то все поля из правой таблицы вернут специальное значение — NULL.

Важное предупреждение: Распространенной ошибкой является наложение условий на правую (присоединяемую) таблицу в секции ГДЕ. Рассмотрим этот пример подробнее:


// ТАК ДЕЛАТЬ НЕЛЬЗЯ! Левое соединение превратится во внутреннее
ВЫБРАТЬ
    Контрагенты.Ссылка КАК Организация,
    Настройки.ВебСервер КАК ВебСервер
ИЗ
    Справочник.Контрагенты КАК Контрагенты
    ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.НастройкаВебСерверов.СрезПоследних КАК Настройки
        ПО Контрагенты.Ссылка = Настройки.Организация
ГДЕ
    Настройки.Рабочая = ИСТИНА // ОШИБКА! Строки с NULL будут отброшены

Поскольку для отсутствующих в регистре организаций поле Настройки.Рабочая примет значение NULL, условие NULL = ИСТИНА вернет ложь. В результате СУБД просто отбросит все строки, для которых нет настроек, и левое соединение фактически превратится во внутреннее. Чтобы этого избежать, любые фильтры на присоединяемую таблицу нужно накладывать исключительно в параметрах самой виртуальной таблицы.

Различия между NULL, Неопределено и Пустой ссылкой

Для корректного написания условий в 1С крайне важно различать три вида «пустоты»:

Использование конструкции ВЫБОР вместо ЕСТЬNULL

В запросах часто используют функцию ЕСТЬNULL(Поле, ЗначениеЗамены). Например: ЕСТЬNULL(Настройки.ВебСервер, "НЕ настроен"). Однако у этой функции есть важная особенность: тип возвращаемого значения приводится к типу первого аргумента.

Если в конфигураторе для ресурса ВебСервер задана длина строки, например, 10 символов, то строка замены "НЕ настроен" (длина которой 11 символов) будет безжалостно обрезана до 10 символов (получится "НЕ настрое"). Для текстовых статусов гораздо безопаснее и гибче использовать конструкцию ВЫБОР, которая динамически определяет наиболее подходящий тип:


ВЫБОР
    КОГДА Настройки.Организация ЕСТЬ NULL ТОГДА "НЕ настроен"
    ИНАЧЕ "Настроено"
КОНЕЦ КАК СтатусНастройки

Оптимальное решение задачи (пошаговое руководство)

Рассмотрим по шагам реализацию этой задачи для обычной формы, где на форме размещена таблица значений ТаблицаНаФорме с колонками Организация и ВебСервер.

Шаг 1. Создание и настройка запроса

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


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	Контрагенты.Ссылка КАК Организация,
    |	ВЫБОР
    |		КОГДА Настройки.Организация ЕСТЬ NULL ТОГДА ""НЕ настроен""
    |		ИНАЧЕ Настройки.ВебСервер
    |	КОНЕЦ КАК ВебСервер
    |ИЗ
    |	Справочник.Контрагенты КАК Контрагенты
    |	ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.НастройкаВебСерверов.СрезПоследних(
    |		,
    |		Организация В ИЕРАРХИИ(&ЮрЛица)
    |	) КАК Настройки
    |	ПО Контрагенты.Ссылка = Настройки.Организация
    |ГДЕ
    |	Контрагенты.Ссылка В ИЕРАРХИИ(&ЮрЛица)
    |	И НЕ Контрагенты.ЭтоГруппа";

Запрос.УстановитьParameter("ЮрЛица", Справочники.Контрагенты.НайтиПоКоду("У00000127"));

Шаг 2. Заполнение таблицы на форме

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


РезультатЗапроса = Запрос.Выполнить();
Выборка = РезультатЗапроса.Выбрать();

// Очищаем старые данные на форме перед заполнением
ТаблицаНаФорме.Очистить();

Пока Выборка.Следующий() Цикл
    НоваяСтрока = ТаблицаНаФорме.Добавить();
    ЗаполнитьЗначенияСвойств(НоваяСтрока, Выборка);
КонецЦикла;

Дополнительный сценарий: Поиск только ненастроенных контрагентов (Anti-Join)

Иногда перед разработчиком ставится альтернативная задача: вывести на форму исключительно тех контрагентов, по которым вообще нет записей в регистре сведений (чтобы пользователь сразу видел, кого нужно настроить). Такой подход в базах данных называется Anti-Join.

Для этого нам достаточно модифицировать секцию ГДЕ нашего запроса, проверяя ключевое поле присоединенной таблицы на NULL:


ЗапросНенастроенные = Новый Запрос;
ЗапросНенастроенные.Текст = 
    "ВЫБРАТЬ
    |	Контрагенты.Ссылка КАК Организация,
    |	""НЕ настроен"" КАК ВебСервер
    |ИЗ
    |	Справочник.Контрагенты КАК Контрагенты
    |	ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.НастройкаВебСерверов.СрезПоследних(
    |		,
    |		Организация В ИЕРАРХИИ(&ЮрЛица)
    |	) КАК Настройки
    |	ПО Контрагенты.Ссылка = Настройки.Организация
    |ГДЕ
    |	Контрагенты.Ссылка В ИЕРАРХИИ(&ЮрЛица)
    |	И НЕ Контрагенты.ЭтоГруппа
    |	И Настройки.Организация ЕСТЬ NULL"; // Выбираем только те строки, которых нет в регистре

ЗапросНенастроенные.УстановитьПараметр("ЮрЛица", Справочники.Контрагенты.НайтиПоКоду("У00000127"));

Архитектурный совет по разделению данных и интерфейса

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

Гораздо правильнее возвращать из запроса булевый флаг настройки (например, ИСТИНА/ЛОЖЬ), а красивое текстовое представление или подсветку цветом делать на уровне интерфейса:

  1. В запросе получить поле: ВЫБОР КОГДА Настройки.Организация ЕСТЬ NULL ТОГДА ЛОЖЬ ИНАЧЕ ИСТИНА КОНЕЦ КАК Настроено.
  2. Для обычной формы использовать обработчик события ПриВыводеСтроки табличного поля. В нем можно закрасить ненастроенные строки красным цветом или вывести пиктограмму статуса.
  3. Для управляемых форм использовать стандартный механизм Условного оформления динамического списка или таблицы значений, настроив правила отображения без написания кода.
← На главную