Как правильно обновить значения элементов справочника в 1С и исправить ошибку «Элемент не выбран!»

Программист 1С v8.3 (Управляемые формы)
← На главную

При разработке обработок по загрузке или обновлению данных в 1С начинающие программисты часто сталкиваются с ситуацией, когда код поиска элемента вроде бы написан правильно, но при попытке изменить данные система выдает ошибку «Элемент не выбран!». Чаще всего это происходит на этапе вызова метода ПолучитьОбъект(). В этой статье мы подробно разберем, почему возникает эта ошибка, как правильно проверять результаты поиска и как сделать процесс обновления данных профессиональным и быстрым.

Разбор причины ошибки: Ссылка против Числа

Рассмотрим ситуацию, описанную в исходном вопросе. Автор использует методы НайтиПоРеквизиту(), НайтиПоКоду() и НайтиПоНаименованию(). Проблема заключается в строке условия:


Если НайденныйЭлемент <> 0 Тогда
    НайденныйЭлементОбъект = НайденныйЭлемент.ПолучитьОбъект();
    // ... обновление полей
КонецЕсли;

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

В 1С сравнение ссылки с числом 0 всегда будет давать результат Истина (они не равны), даже если ссылка пустая. В итоге программа заходит внутрь условия Если, пытается выполнить ПолучитьОбъект() от пустой ссылки, и система закономерно сообщает: «Элемент не выбран!», так как невозможно получить объект из «пустоты».

Как правильно проверять результат поиска

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

Способ 1. Метод Пустая()

У любого ссылочного типа в 1С есть встроенный метод Пустая(), который возвращает Истина, если ссылка не указывает на реальную запись в базе данных. Это самый явный и читаемый способ.


Если НЕ НайденныйЭлемент.Пустая() Тогда
    НайденныйЭлементОбъект = НайденныйЭлемент.ПолучитьОбъект();
    // Здесь код изменения объекта
КонецЕсли;

Способ 2. Глобальная функция ЗначениеЗаполнено()

Эта функция является универсальной. Она корректно определяет, заполнена ли переменная, будь то ссылка, строка, число или дата. Для ссылок она вернет Ложь, если ссылка пустая.


Если ЗначениеЗаполнено(НайденныйЭлемент) Тогда
    НайденныйЭлементОбъект = НайденныйЭлемент.ПолучитьОбъект();
    // Изменяем реквизиты
    НайденныйЭлементОбъект.Записать();
КонецЕсли;

Оптимизация: Почему поиск в цикле — это плохо

Выяснив причину ошибки, давайте проанализируем архитектуру кода. В примере автора поиск выполняется внутри цикла Для Каждого Строка Из ТЗ. Если в вашей таблице 1000 строк, система выполнит 1000 отдельных запросов к базе данных. Это крайне неэффективно и может привести к зависанию программы на больших объемах данных.

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

  1. Выгружаем колонку с ключами поиска (например, Артикулы) из таблицы значений в массив.
  2. Передаем этот массив в запрос.
  3. В запросе соединяем массив с таблицей справочника Справочники.Номенклатура.
  4. Получаем результат запроса, который содержит сразу все найденные ссылки.
  5. Обходим результат запроса и обновляем данные.

Такой подход сокращает количество обращений к серверу базы данных до одного, что ускоряет работу в десятки раз.

Использование режима загрузки данных

При массовом обновлении справочников важно помнить о бизнес-логике, заложенной в конфигурацию. В справочниках часто прописаны проверки в процедурах ПередЗаписью или ПриЗаписи. Чтобы ускорить процесс и избежать лишних проверок (например, проверки заполнения Группы, если вы её не меняете), используйте свойство ОбменДанными.Загрузка.

Проанализируем пример правильной записи объекта:


НайденныйЭлементОбъект = НайденныйЭлемент.ПолучитьОбъект();
НайденныйЭлементОбъект.ОбменДанными.Загрузка = Истина; 
// Установка этого свойства отключает большинство проверок при записи
НайденныйЭлементОбъект.Артикул = Строка.Артикул;
// ... заполнение остальных полей
НайденныйЭлементОбъект.Записать();

Важные нюансы: Индексирование и Транзакции

Для того чтобы метод НайтиПоРеквизиту() работал быстро, проверьте настройки этого реквизита в Конфигураторе. Поле, по которому осуществляется поиск (например, Артикул), должно иметь включенное свойство «Индексировать». Без индекса система будет перебирать все записи справочника по порядку, что на базе в 100 000 элементов займет значительное время.

Также рекомендуется оборачивать цикл обновления в Транзакцию. Это обеспечит целостность данных: если в процессе обновления 500-го элемента произойдет критическая ошибка, изменения предыдущих 499 элементов не будут зафиксированы в базе, и вы не получите «кашу» из полуобновленных данных.


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

Заключение

Подведем итоги нашего разбора. Ошибка «Элемент не выбран!» — это сигнал о том, что вы пытаетесь работать с объектом, имея пустую ссылку. Всегда проверяйте результат поиска с помощью ЗначениеЗаполнено() или метода Пустая().

Для написания качественного кода придерживайтесь следующих правил:

Следуя этим советам, вы не только исправите текущую ошибку, но и значительно повысите производительность и стабильность вашей системы.

← На главную