Как исправить ошибку «Поле объекта не найдено» при обращении к реквизиту через точку на клиенте?

Программист 1С v8.3 (Управляемые формы) 1С:Управление нашей фирмой Управленческий учет Торговля и дистрибуция
← На главную

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

Рассмотрим классический пример: в клиентской процедуре (с директивой &НаКлиенте) есть код, который обращается к реквизиту номенклатуры СтрокаТабличнойЧасти.Номенклатура.Длина. В рабочей базе все работает, а в копии — нет. Давайте разберемся, почему так происходит и как это правильно исправить.

Выясняем причину: особенности клиент-серверной архитектуры

Корень проблемы лежит в фундаментальных принципах работы управляемых форм и разделении кода на клиентский и серверный.

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

На сервере (&НаСервере), наоборот, есть полный доступ ко всей базе данных. Серверный код может по ссылке получить сам объект и прочитать любые его реквизиты.

Так почему же код работал в старой базе?

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

Новая же база, скорее всего, запускается в режиме «Тонкий клиент» или «Веб-клиент» (даже если в настройках запуска стоит «Автоматически»). Эти клиенты строго следуют идеологии разделения данных, и на клиент передаются только ссылки, что и приводит к закономерной ошибке.

Решение 1: Архитектурно верный способ (рекомендуемый)

Правильное решение — не пытаться заставить старый код работать, а исправить его в соответствии с принципами клиент-серверного взаимодействия. Для получения данных объекта по ссылке на клиенте нужно явно вызвать серверную процедуру.

Разберем по шагам на примере изначальной проблемы. Был код:


// Этот код вызывает ошибку на тонком клиенте
Если СтрокаТабличнойЧасти.Номенклатура.Длина > 0 И СтрокаТабличнойЧасти.Номенклатура.Объем = 0 Тогда
    СтрокаТабличнойЧасти.Куб1 = СтрокаТабличнойЧасти.Номенклатура.Длина * СтрокаТабличнойЧасти.Количество;
Иначе    
    СтрокаТабличнойЧасти.Куб1 = СтрокаТабличнойЧасти.Номенклатура.Объем * СтрокаТабличнойЧасти.Количество;
КонецЕсли;

Чтобы исправить его, выполним следующие действия:

  1. Создадим серверную функцию. Эту функцию можно разместить в модуле формы или в общем модуле (если она будет использоваться в нескольких местах). Функция будет принимать ссылку на номенклатуру и возвращать структуру с нужными нам реквизитами.

    Для получения данных лучше использовать запрос — это самый производительный способ.

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

    
    &НаКлиенте
    Процедура РассчитатьСуммыВСтроке()
        
        // ... получаем текущую строку, например:
        // СтрокаТабличнойЧасти = Элементы.Товары.ТекущиеДанные;
        
        // Вызываем серверную функцию для получения данных
        Габариты = ПолучитьГабаритыНоменклатуры(СтрокаТабличнойЧасти.Номенклатура);
        
        // Используем полученные данные из структуры
        Если Габариты.Длина > 0 И Габариты.Объем = 0 Тогда
            СтрокаТабличнойЧасти.Куб1 = Габариты.Длина * СтрокаТабличнойЧасти.Количество;
        Иначе    
            СтрокаТабличнойЧасти.Куб1 = Габариты.Объем * СтрокаТабличнойЧасти.Количество;
        КонецЕсли;
        
        // ... дальнейший код расчета
        
    КонецПроцедуры
    

Преимущества этого подхода:

Решение 2: Принудительный запуск в толстом клиенте (обходной путь)

Если по каким-то причинам нет возможности или времени исправлять код, можно воспользоваться временным решением — заставить новую базу работать в том же режиме, что и старую.

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

  1. Измените настройки запуска базы. В окне запуска 1С выберите вашу базу, нажмите «Изменить». В параметрах запуска найдите поле «Основной режим запуска» и вместо «Выбирать автоматически» установите «Толстый клиент».

  2. Очистите кэш. Иногда платформа некорректно применяет смену режима запуска из-за старого кэша. Если после смены режима ошибка осталась, обязательно очистите кэш конфигурации. Проще всего это сделать, удалив базу из списка и добавив ее заново, сразу указав режим запуска «Толстый клиент».

  3. Проверьте права пользователя. Убедитесь, что у пользователя, под которым происходит запуск, есть права на использование толстого клиента. Эти права настраиваются в ролях конфигурации.

Этот способ заставит платформу вести себя так же, как в старой базе, и ошибка, скорее всего, исчезнет. Но помните, что при первой же необходимости запустить базу в тонком или веб-клиенте проблема вернется.

Таким образом, столкнувшись с ошибкой «Поле объекта не найдено», всегда анализируйте, где выполняется ваш код. В 99% случаев это сигнал о том, что вы пытаетесь на клиенте получить данные, которые доступны только на сервере. Использование явных серверных вызовов — это не только правильное решение проблемы, но и залог создания стабильного и предсказуемого кода.

← На главную