Как пропустить пустые значения в цикле и избежать ошибки заполнения в 1С?

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

При разработке обработок по переносу данных или заполнению дополнительных свойств объектов программисты часто сталкиваются с системной ошибкой: "Значение поля свойства не может быть пустым". Эта ситуация возникает, когда в конфигурации для ресурса или реквизита регистра сведений установлено требование обязательного заполнения, а программный код пытается передать туда неопределенное значение, ноль или пустую ссылку. Разберем подробно, как правильно настроить исключения в цикле Пока и оптимизировать этот процесс.

Причина возникновения ошибки

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

Решение 1: Фильтрация на уровне запроса (оптимальный способ)

Самый правильный подход в архитектуре 1С — не выбирать лишние данные из базы. Если нам не нужны записи с пустым объемом, мы должны отсечь их еще на этапе выполнения запроса. Это значительно снижает нагрузку на сервер и ускоряет работу цикла, так как итераций становится меньше.

Проанализируем, как изменить текст запроса. Если поле Объем имеет числовой тип, мы добавляем условие ГДЕ ... <> 0. Если это ссылка — проверяем на пустую ссылку. Однако наиболее универсальным способом является проверка на NULL и использование функции ЗНАЧЕНИЕЗАПОЛНЕНО (в коде) или условий в запросе.


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	Номенклатура.ЕдиницаХраненияОстатков.Владелец КАК Номенклатура,
    |	Номенклатура.ЕдиницаХраненияОстатков.Объем КАК Объем
    |ИЗ
    |	Справочник.Номенклатура КАК Номенклатура
    |ГДЕ
    |	Номенклатура.ЕдиницаХраненияОстатков.Объем <> 0
    |	И Номенклатура.ЕдиницаХраненияОстатков.Объем ЕСТЬ НЕ NULL";

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

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

Решение 2: Использование оператора Продолжить в цикле

Если по каким-то причинам вы не можете изменить запрос, или проверка должна быть сложной и выполняться на встроенном языке, используйте оператор Продолжить. Рассмотрим типичную ошибку начинающих: вызов метода Выборка.Следующий() внутри тела цикла для "пропуска". Это неверно, так как такой вызов перескакивает через одну запись, и вы теряете данные.

Правильная логика выглядит так: мы проверяем условие, и если данные нас не устраивают, немедленно переходим к следующей итерации цикла с помощью команды Продолжить.


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

Пока ВыборкаДетальныеЗаписи.Следующий() Цикл
    
    // Используем универсальную функцию ЗначениеЗаполнено
    Если Не ЗначениеЗаполнено(ВыборкаДетальныеЗаписи.Объем) Тогда
        Продолжить; // Пропускаем запись и идем к следующей номенклатуре
    КонецЕсли;
    
    // Логика записи в регистр
    МенеджерЗаписи = РегистрыСведений.ЗначенияСвойствОбъектов.СоздатьМенеджерЗаписи();
    МенеджерЗаписи.Объект   = ВыборкаДетальныеЗаписи.Номенклатура;
    МенеджерЗаписи.Свойство = ОбъемМ3;
    МенеджерЗаписи.Значение = ВыборкаДетальныеЗаписи.Объем;
    
    Попытка
        МенеджерЗаписи.Записать();
    Исключение
        Сообщить("Ошибка при записи объекта: " + ВыборкаДетальныеЗаписи.Номенклатура);
    КонецПопытки;
    
КонецЦикла;

Обратите внимание на функцию ЗначениеЗаполнено(). В 1С это наиболее надежный способ проверки, так как она корректно отрабатывает для всех типов данных: чисел, строк, дат и ссылок.

Решение 3: Проверка типов в Плане Видов Характеристик

Регистр ЗначенияСвойствОбъектов обычно связан с Планом Видов Характеристик (ПВХ). У каждого свойства в ПВХ определен свой Тип значения. Если вы пытаетесь записать число в свойство, которое предназначено для хранения справочника "Цвета", платформа также выдаст ошибку.

Разберем, как добавить проверку на соответствие типов перед записью. Это поможет избежать падения обработки, если в базе данных есть некорректно настроенные свойства.


Если Не ОбъемМ3.ТипЗначения.СодержитТип(ТипЗнч(ВыборкаДетальныеЗаписи.Объем)) Тогда
    Сообщить("Тип значения объема не соответствует настройкам свойства!");
    Продолжить;
КонецЕсли;

Оптимизация производительности: Набор записей вместо Менеджера

В исходном коде темы используется СоздатьМенеджерЗаписи() внутри цикла. Проанализируем этот момент: при каждой итерации программа создает новый объект, обращается к базе для чтения, а затем для записи. Если у вас 10 000 товаров, это 20 000 лишних обращений к СУБД.

Для массового заполнения свойств гораздо эффективнее использовать Набор записей. Рассмотрим, как переписать код для ускорения работы:

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

Либо, если мы обновляем записи по одной, всё равно лучше минимизировать действия:


НаборЗаписей = РегистрыСведений.ЗначенияСвойствОбъектов.СоздатьНаборЗаписей();

Пока ВыборкаДетальныеЗаписи.Следующий() Цикл
    Если Не ЗначениеЗаполнено(ВыборкаДетальныеЗаписи.Объем) Тогда 
        Продолжить; 
    КонецЕсли;

    НаборЗаписей.Отбор.Объект.Установить(ВыборкаДетальныеЗаписи.Номенклатура);
    НаборЗаписей.Отбор.Свойство.Установить(ОбъемМ3);
    
    НоваяЗапись = НаборЗаписей.Добавить();
    НоваяЗапись.Объект = ВыборкаДетальныеЗаписи.Номенклатура;
    НоваяЗапись.Свойство = ОбъемМ3;
    НоваяЗапись.Значение = ВыборкаДетальныеЗаписи.Объем;
    
    НаборЗаписей.Записать(); // Это работает быстрее менеджера в массовых операциях
КонецЦикла;

Использование транзакций

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


НачатьТранзакцию();
Попытка
    Пока ВыборкаДетальныеЗаписи.Следующий() Цикл
        // ... код проверки и записи ...
    КонецЦикла;
    ЗафиксироватьТранзакцию();
Исключение
    ОтменитьТранзакцию();
    Сообщить("Произошла критическая ошибка, изменения отменены: " + ОписаниеОшибки());
КонецПопытки;

Резюмируем: для устранения ошибки "Значение поля свойства не может быть пустым", в первую очередь добавьте условие ГДЕ ... <> 0 в ваш запрос. Если это невозможно, используйте проверку ЗначениеЗаполнено() в начале цикла вместе с оператором Продолжить. Это сделает ваш код стабильным, читаемым и профессиональным.

← На главную