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

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

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

Выясняем причину ошибки

Рассмотрим ситуацию, с которой столкнулся автор темы. В документе-приемнике в процедуре ОбработкаЗаполнения выполняется обход табличной части документа-источника:


Для Каждого ТекСтрокаТМЗ Из ДанныеЗаполнения.ТМЗ Цикл
    НоваяСтрока = ТМЗ.Добавить();
    // ... записание других реквизитов
    НоваяСтрока.Основание = ТекСтрокаТМЗ.Ссылка; // Ошибка возникает здесь!
КонецЦикла;

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

Причина кроется в особенностях объектной модели платформы «1С:Предприятие»:

  1. Разница типов данных: Переменная ТекСтрокаТМЗ внутри цикла имеет тип ДокументТабличнаяЧастьСтрока. Строка табличной части в оперативной памяти — это простой объект, содержащий только индекс строки и значения ее реквизитов (колонок). Она не является ссылочным типом данных и не хранит в себе ссылку на документ-владелец.
  2. Путаница с языком запросов 1С: Разработчики часто переносят логику работы запросов во встроенный язык. В запросах к табличным частям документов виртуальное поле Ссылка действительно существует и возвращает ссылку на документ-владелец. Однако в объектной технике (в коде модуля) у строки табличной части такого свойства нет.

Поскольку ссылка на документ-источник уже передана в процедуру в качестве параметра ДанныеЗаполнения, обращаться к строке ТЧ за ссылкой нет никакой необходимости.

Решение проблемы и устранение избыточности кода

Для исправления ошибки достаточно напрямую присвоить реквизиту Основание значение параметра ДанныеЗаполнения. Изменим код следующим образом:

НоваяСтрока.Основание = ДанныеЗаполнения;

Некоторые разработчики (как показано в Сообщении 2 форума) предлагают использовать конструкцию ДанныеЗаполнения.Ссылка. Давайте проанализируем, почему это решение работает, но является избыточным.

Если перед циклом мы уже выполнили проверку типа:

Если ТипЗнч(ДанныеЗаполнения) = Тип("ДокументСсылка.ПоступлениеТМЗ") Тогда

то переменная ДанныеЗаполнения гарантированно содержит ссылку. Обращение к свойству .Ссылка у самой ссылки (то есть получение ссылки от ссылки) синтаксически допустимо в 1С, но это лишняя операция, которая не несет никакой практической пользы.

Однако в типовых конфигурациях 1С от фирмы «1С» мы действительно можем встретить код вида ДанныеЗаполнения.Ссылка. Это делается по двум причинам:

Лучшие практики написания обработчика заполнения

Теперь, когда мы выяснили причину ошибки, давайте разберем, как сделать наш код более профессиональным, быстрым и соответствующим стандартам разработки (например, БСП).

Способ 1. Использование метода ЗаполнитьЗначенияСвойств()

Вместо того чтобы вручную сопоставлять и переносить каждый реквизит строки (например, Номенклатура, Количество, Цена), мы можем использовать эффективный встроенный метод ЗаполнитьЗначенияСвойств(). Он автоматически найдет свойства с одинаковыми именами в источнике и приемнике и скопирует их значения.


Для Каждого ТекСтрокаТМЗ Из ДанныеЗаполнения.ТМЗ Цикл
    НоваяСтрока = ТМЗ.Добавить();
    ЗаполнитьЗначенияСвойств(НоваяСтрока, ТекСтрокаТМЗ);
    НоваяСтрока.Основание = ДанныеЗаполнения; 
КонецЦикла;

Способ 2. Добавление проверок бизнес-логики

Согласно стандартам разработки 1С, перед выполнением заполнения на основании необходимо убедиться в корректности данных источника. Например, не рекомендуется разрешать ввод на основании непроведенных документов или документов, помеченных на удаление.

Рассмотрим финальный вариант качественной реализации процедуры ОбработкаЗаполнения:


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

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

← На главную