Как обратиться к реквизитам ссылки в табличной части документа

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

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

Выясним причину ошибки: Клиент против Сервера

Рассмотрим ситуацию: у нас есть документ Производство, в табличной части которого выбрана Номенклатура. У номенклатуры есть числовой реквизит Fe (содержание железа). Мы хотим использовать это число в расчетах прямо в строке документа. Проблема заключается в том, что на клиенте объект ссылки представляет собой лишь идентификатор и строковое представление. Физически данных реквизита Fe в оперативной памяти клиентского приложения нет.

Проанализируем типичный ошибочный код на клиенте:


&НаКлиенте
Процедура ТабличнаяЧастьКоличествоПриИзменении(Элемент)
    СтрокаТаблицы = Элементы.ТабличнаяЧасть.ТекущиеДанные;
    // ОШИБКА: Поле объекта не обнаружено (Fe)
    Результат = СтрокаТаблицы.Номенклатура.Fe / 100; 
КонецПроцедуры

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

Решение 1: Расчет на сервере перед записью документа

Если нам не нужно показывать результат расчета пользователю мгновенно, а достаточно зафиксировать его при сохранении документа, мы можем использовать обработчик ПередЗаписью. В этом случае мы работаем с объектом документа, который полностью доступен на сервере.

Разберем по шагам реализацию этого метода:

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

Пример кода в модуле документа:


Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
    Для Каждого СтрокаДокумента Из Состав Цикл
        // Проверяем, выбрана ли номенклатура
        Если ЗначениеЗаполнено(СтрокаДокумента.Номенклатура) Тогда
            // На сервере обращение через точку работает напрямую
            СтрокаДокумента.РезультатРасчета = (СтрокаДокумента.Номенклатура.Fe / 100) * СтрокаДокумента.Количество;
        КонецЕсли;
    КонецЦикла;
КонецПроцедуры

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

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

Проанализируем пример реализации:


&НаКлиенте
Процедура СоставНоменклатураПриИзменении(Элемент)
    СтрокаТаблицы = Элементы.Состав.ТекущиеДанные;
    Если СтрокаТаблицы <> Неопределено Тогда
        // Вызываем серверную функцию для получения данных
        СтрокаТаблицы.СодержаниеЖелеза = ПолучитьЗначениеFeНаСервере(СтрокаТаблицы.Номенклатура);
    КонецЕсли;
КонецПроцедуры

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

Обратите внимание на использование директивы &НаСервереБезКонтекста. Это критически важно для производительности: в этом режиме на сервер не передается вся форма, а только конкретный параметр (ссылка), что значительно ускоряет работу программы.

Важный аспект: Производительность и обращение через точку

Хотя обращение СтрокаДокумента.Номенклатура.Fe на сервере выглядит простым, оно имеет скрытую проблему. Каждый такой вызов — это отдельный неявный запрос к базе данных (SQL-запрос). Если в вашей табличной части 200 строк, система выполнит 200 маленьких запросов, что может замедлить работу сервера.

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


&НаСервере
Процедура РассчитатьВсеСтрокиТаблицы()
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |   Номенклатура.Fe КАК Железо,
        |   Номенклатура.Ссылка КАК Ссылка
        |ИЗ
        |   Справочник.Номенклатура КАК Номенклатура
        |ГДЕ
        |   Номенклатура.Ссылка В (&МассивСсылок)";
    
    МассивНоменклатуры = Объект.Состав.ВыгрузитьКолонку("Номенклатура");
    Запрос.УстановитьПараметр("МассивСсылок", МассивНоменклатуры);
    
    РезультатЗапроса = Запрос.Выполнить().Выгрузить();
    
    Для Каждого СтрокаТЧ Из Объект.Состав Цикл
        СтрокаДанных = РезультатЗапроса.Найти(СтрокаТЧ.Номенклатура, "Ссылка");
        Если СтрокаДанных <> Неопределено Тогда
            СтрокаТЧ.СодержаниеЖелеза = СтрокаДанных.Железо;
        КонецЕсли;
    КонецЦикла;
КонецПроцедуры

Архитектурный подход: Дублирование данных

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

Правильное решение: Создайте в табличной части документа реквизит ПроцентЖелеза. При выборе номенклатуры один раз скопируйте значение из справочника в этот реквизит документа. Это «заморозит» состояние данных на момент совершения операции. Все дальнейшие расчеты делайте только на основании реквизитов самого документа.

Использование метода «Путь к данным» в элементах формы

Существует еще один способ увидеть данные из справочника на форме без написания кода. В свойствах колонки таблицы на форме можно указать ПутьКДанным как Объект.Состав.Номенклатура.Fe. В этом случае система сама отобразит число в колонке.

Однако помните:

Резюме

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

  1. Никогда не обращайтесь к реквизитам ссылки через точку на клиенте — это гарантированная ошибка.
  2. Для интерактивного обновления используйте вызов &НаСервереБезКонтекста.
  3. Всегда проверяйте ссылку на пустое значение через ЗначениеЗаполнено() перед получением свойств.
  4. Для массовой обработки строк используйте Запрос вместо обращения через точку в цикле.
  5. Копируйте важные для расчета значения из справочников в реквизиты документа, чтобы обеспечить неизменность истории учета.
← На главную