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