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

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

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

Разберем основную причину проблемы: Клиент против Сервера

Проанализируем ситуацию, описанную в теме. Разработчик пытается получить значение НомерЗаказа, обращаясь к нему напрямую из ссылки в строке табличной части в обработчике ПриОткрытии(). Основная ошибка здесь заключается в непонимании контекста выполнения кода. Процедура ПриОткрытии() выполняется на клиенте.

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

Решение 1: Перенос заполнения данных на сторону сервера

Самый простой и логичный способ решить проблему — перенести алгоритм обхода строк табличной части в серверный контекст. На сервере платформа имеет прямой доступ к базе данных и может легко "прочитать" реквизиты по ссылке. Выясним, как это реализовать правильно в расширении.

Вместо использования клиентского события ПриОткрытии(), нам следует использовать серверное событие ПриСозданииНаСервере() или ПриЧтенииНаСервере(). Если же нам необходимо обновить данные в процессе работы пользователя, нужно создать внеконтекстную серверную процедуру.

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


&НаСервере
Процедура ЗаполнитьДополнительныеРеквизитыНаСервере()
    
    // Получаем коллекцию элементов дерева или таблицы
    КоллекцияСтрок = ДеревоРаспределенияСуммыПлатежа.ПолучитьЭлементы();
    
    Для Каждого СтрокаТЧ Из КоллекцияСтрок Цикл
        
        // На сервере обращение через точку работает корректно
        Если ЗначениеЗаполнено(СтрокаТЧ.Объект) Тогда
            // Платформа автоматически выполнит неявный запрос к БД
            СтрокаТЧ.НомерЗаказа = СтрокаТЧ.Объект.НомерЗаказа;
        КонецЕсли;
        
    КонецЦикла;
    
КонецПроцедуры

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

Существует элегантный способ вывести реквизит связанного документа вообще без написания кода на языке 1С. Этот метод позволяет платформе самой заботиться о доставке данных на клиент. Проанализируем, как это сделать в расширении:

  1. Добавим в расширение необходимый документ и его реквизит (например, ЗаказПокупателя и его реквизит Номер).
  2. В форме обработки выберем нашу табличную часть.
  3. Добавим новый ЭлементФормы типа ПолеВвода в эту таблицу.
  4. В свойстве ПутьКДанным укажем путь через точку от основного реквизита таблицы. Например: Объект.СписокЗаказов.СсылкаНаЗаказ.Номер.

При таком подходе платформа 1С автоматически включает чтение этого поля в стандартный запрос при получении данных формы. Это работает максимально быстро и избавляет от лишних серверных вызовов в ПриОткрытии.

Решение 3: Оптимизация производительности (Запросы)

Рассмотрим ситуацию, когда таблица содержит сотни или тысячи строк. Обращение к реквизиту через точку в цикле (как в первом решении) порождает проблему, известную как "N+1 запрос". На каждой итерации цикла платформа будет делать отдельный запрос к базе данных, чтобы получить объект целиком. Это критически замедляет работу программы.

Чтобы избежать этой проблемы, проанализируем ситуацию и применим объект Запрос. Посмотрим на пример эффективного заполнения:


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

Особенности работы в расширении

При работе через расширение важно учитывать еще несколько технических моментов, без которых доступ к реквизитам может быть закрыт даже на сервере:

  1. Заимствование реквизитов: Убедимся, что в расширение добавлен не только сам документ (как тип данных), но и конкретные реквизиты этого документа. Если в расширении есть Документ.ЗаказПокупателя, но не добавлен его реквизит НомерЗаказа, программный код расширения может не "видеть" это поле.
  2. Безопасный режим: Расширения часто подключаются в безопасном режиме. Проверьте в свойствах расширения (в конфигураторе или в пользовательском режиме), не стоит ли галочка "Безопасный режим". В некоторых случаях это может ограничивать доступ к метаданным.
  3. Типизация: Если колонка в табличной части имеет составной тип данных, при обращении "через точку" на сервере платформа сначала попытается определить конкретный тип ссылки. Если типов много, это также может замедлить работу.

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

← На главную