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