Как исправить ошибку «Поле объекта не обнаружено» при расчете цены и суммы в 1С?

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

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

Разбор причины 1: Обращение к пустой ссылке

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


Функция ПолучитьЦену(ЭлементЗначение) 
    Спр = Справочники.Пиццы;
    НайденнаяЦена = Спр.НайтиПоНаименованию(ЭлементЗначение).Цена;
    Возврат НайденнаяЦена;
КонецФункции

Выясним причину сбоя. Метод НайтиПоНаименованию() возвращает ссылку на объект справочника. Однако, если объект с таким именем не найден (например, в справочнике «Пиццы» нет элемента с текстом, переданным в ЭлементЗначение), система вернет Пустую ссылку. У пустой ссылки нет реквизита Цена. Именно в этот момент программа выдает ошибку «Поле объекта не обнаружено».

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


&НаСервере
Функция ПолучитьЦену(ПиццаСсылка)
    // Проверяем, не является ли переданная ссылка пустой
    Если ПиццаСсылка.Пустая() Тогда
        Возврат 0;
    КонецЕсли;
    
    // Возвращаем значение реквизита напрямую
    Возврат ПиццаСсылка.Цена;
КонецФункции

Разбор причины 2: Ошибка типизации и перезапись переменной

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


&НаКлиенте
Процедура ЗаказПозицияПриИзменении(Элемент)
    СтрокаТабличнойЧасти = Элементы.Заказ.ТекущиеДанные;
    СтрокаТабличнойЧасти.Цена = ПолучитьЦену(СтрокаТабличнойЧасти.Позиция);
    СтрокаТабличнойЧасти = СтрокаТабличнойЧасти.Цена * СтрокаТабличнойЧасти.Количество; // ОШИБКА ЗДЕСЬ
КонецПроцедуры

Проанализируем, что происходит с переменной СтрокаТабличнойЧасти. Сначала в ней хранится объект (строка таблицы), который имеет свойства Цена, Количество и Сумма. Но в последней строке разработчик случайно присваивает этой же переменной результат умножения (число). После этого переменная перестает быть «строкой таблицы» и становится просто «числом». Любое дальнейшее обращение к полям через эту переменную вызовет ошибку.

Исправленный вариант должен выглядеть так:


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

    // Присваиваем значение КОНКРЕТНОМУ ПОЛЮ строки
    СтрокаТабличнойЧасти.Цена = ПолучитьЦену(СтрокаТабличнойЧасти.Позиция);
    
    // Рассчитываем сумму и записываем ее в поле Сумма
    СтрокаТабличнойЧасти.Сумма = СтрокаТабличнойЧасти.Цена * СтрокаТабличнойЧасти.Количество;
КонецПроцедуры

Оптимизация клиент-серверного взаимодействия

Рассмотрим вопрос производительности. В 1С 8.3 управляемые формы работают в контексте «Клиент» и «Сервер». Каждый вызов функции &НаСервере заставляет программу передавать данные всей формы на сервер и обратно.

Для простых операций, таких как получение цены по ссылке, лучше использовать директиву &НаСервереБезКонтекста. Это значительно ускорит работу формы, так как на сервер передастся только один параметр, а не вся форма целиком.

Посмотрим на пример оптимизированного кода:


&НаКлиенте
Процедура ЗаказПозицияПриИзменении(Элемент)
    ТекущаяСтрока = Элементы.Заказ.ТекущиеДанные;
    Если ТекущаяСтрока = Неопределено Тогда
        Возврат;
    КонецЕсли;
    
    // Передаем только ссылку на номенклатуру
    ТекущаяСтрока.Цена = ПолучитьЦенуНаСервере(ТекущаяСтрока.Позиция);
    
    // Выполняем расчет суммы на клиенте
    РассчитатьСуммуСтроки(ТекущаяСтрока);
КонецПроцедуры

&НаСервереБезКонтекста
Функция ПолучитьЦенуНаСервере(СсылкаНаПиццу)
    // Обращение через точку на сервере допустимо, 1С само получит данные из БД
    Возврат СсылкаНаПиццу.Цена; 
КонецФункции

&НаКлиенте
Процедура РассчитатьСуммуСтроки(Строка)
    Строка.Сумма = Строка.Цена * Строка.Количество;
КонецПроцедуры

Профессиональные советы по архитектуре

Для учебных проектов хранение цены прямо в справочнике допустимо, но в реальных бизнес-задачах мы рекомендуем учитывать следующие правила:

  1. Использование Регистров сведений: Цены лучше хранить в периодическом регистре сведений (например, «ЦеныНоменклатуры»). Это позволит хранить историю цен. Если сегодня пицца стоит 500 рублей, а завтра 600, старые заказы должны помнить цену в 500 рублей.
  2. Проверка на заполнение: Всегда проверяйте результат работы методов поиска. Метод ЗначениеЗаполнено(Ссылка) поможет избежать попыток обращения к несуществующим объектам.
  3. Общие процедуры расчета: Создавайте одну общую процедуру для расчета суммы (как в нашем примере выше — РассчитатьСуммуСтроки). Вызывайте её и при изменении цены, и при изменении количества. Это исключит дублирование кода и облегчит поиск ошибок.
  4. Безопасность «Текущих данных»: Всегда добавляйте условие Если ТекущиеДанные = Неопределено. Если пользователь случайно вызовет событие в пустой таблице, ваша программа не «вылетит» с критической ошибкой.

Таким образом, мы выяснили, что ошибка «Поле объекта не обнаружено» — это лишь симптом. Настоящая причина крылась в отсутствии проверки на результат поиска и в некорректном обращении с типами переменных в языке 1С. Используя предложенные методы, вы сможете писать более надежный и быстрый код.

← На главную