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