Как в управляемой форме 1С получить реквизит ссылочного объекта из текущей строки таблицы?

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

При разработке в среде 1С:Предприятие 8 на управляемых формах начинающие разработчики часто сталкиваются с ситуацией, когда при выборе элемента в табличной части (например, номенклатуры) требуется сразу заполнить сопутствующие реквизиты строки — цену, ставку НДС, единицу измерения или артикул. Однако прямая попытка обратиться к реквизиту ссылки на клиенте через точку вида Строка.Товар.РекомендованнаяЦена не приносит желаемого результата или приводит к ошибке. Разберем, почему так происходит и как правильно организовать получение данных в архитектуре управляемого приложения.

Почему обращение через точку не работает на клиенте

Проанализируем ключевое архитектурное отличие управляемых форм от обычных форм. В управляемом приложении клиентский уровень (тонкий или веб-клиент) и серверный уровень строго разделены.

На клиенте ссылочный тип (например, СправочникСсылка.Номенклатура) представляет собой облегченную структуру данных, содержащую только уникальный идентификатор (GUID) и строковое представление для отображения в интерфейсе. Сами данные объекта в памяти клиентского приложения отсутствуют. Любое разыменование ссылки (обращение через точку к реквизитам объекта базы данных) требует выполнения запроса к СУБД, что возможно исключительно на стороне сервера. Поэтому на клиенте платформа блокирует прямое чтение реквизитов через точку.

Строка таблицы на клиенте представляет собой объект типа ДанныеФормыЭлементКоллекции, полученный через свойство Элементы.ИмяТаблицы.ТекущиеДанные. Чтобы получить значение реквизита из базы данных, необходимо передать ссылку на сервер, прочитать значение и вернуть его обратно на клиент.

Способ 1. Получение реквизита через неконтекстный серверный вызов с запросом (Рекомендуемый)

Рассмотрим наиболее производительный и правильный с точки зрения стандартов разработки 1С вариант. Для минимизации объема передаваемых между клиентом и сервером данных используем процедуру с директивой компиляции &НаСервереБезКонтекста и язык запросов 1С.

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


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

КонецПроцедуры

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

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

  1. Минимальный трафик: директива &НаСервереБезКонтекста не передает на сервер все данные формы (контекст), передается только ссылка на номенклатуру и возвращается числовое значение цены.
  2. Оптимальная нагрузка на СУБД: запрос считывает только указанное поле РекомендованнаяЦена, не считывая весь объект целиком из базы данных.
  3. Безопасность: выполняется проверка СтрокаТаблицы = Неопределено, что исключает ошибки при случайной потере фокуса со строки.

Способ 2. Получение данных с использованием функций БСП

Если разработка ведется в типовой или доработанной конфигурации, содержащей Библиотеку стандартных подсистем (БСП), нет необходимости каждый раз вручную писать запросы для чтения отдельных реквизитов. Разберем, как воспользоваться методами общего модуля ОбщегоНазначения:


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

КонецПроцедуры

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

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

Способ 3. Прямое отображение реквизита ссылки в таблице без кода

Выясним ситуацию: что делать, если значение реквизита не требуется перезаписывать в документ, а нужно просто отобразить для пользователя в табличной части для справочной информации?

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

  1. В редакторе формы в окне реквизитов развернем структуру табличной части Объект.Товары.
  2. Раскроем реквизит Номенклатура — платформа покажет список доступных реквизитов самого справочника.
  3. Перетащим нужный реквизит (например, РекомендованнаяЦена) в состав колонок таблицы элементов формы.
  4. Платформа сформирует путь к данным вида Объект.Товары.Номенклатура.РекомендованнаяЦена. Чтение и кэширование значений платформа выполнит автоматически в рамках стандартных интерфейсных механизмов.

Способ 4. Получение цены из регистра сведений

В типовых решениях цены редко хранятся в самом справочнике номенклатуры — для этого используются периодические регистры сведений (например, ЦеныНоменклатуры). Посмотрим, как получить срез последних цен на дату документа:


&НаКлиенте
Процедура ТоварыНоменклатураПриИзменении(Элемент)
    
    СтрокаТаблицы = Элементы.Товары.ТекущиеДанные;
    Если СтрокаТаблицы = Неопределено Тогда
        Возврат;
    КонецЕсли;
    
    СтрокаТаблицы.Цена = ПолучитьАктуальнуюЦену(СтрокаТаблицы.Номенклатура, Объект.Дата, Объект.ВидЦены);

КонецПроцедуры

&НаСервереБезКонтекста
Функция ПолучитьАктуальнуюЦену(НоменклатураСсылка, ДатаДокумента, ВидЦены)
    
    Отбор = Новый Структура;
    Отбор.Вставить("Номенклатура", НоменклатураСсылка);
    Отбор.Вставить("ВидЦены", ВидЦены);
    
    ЗначенияЦены = РегистрыСведений.ЦеныНоменклатуры.СрезПоследних(ДатаДокумента, Отбор);
    
    Если ЗначенияЦены.Количество() > 0 Тогда
        Возврат ЗначенияЦены[0].Цена;
    КонецЕсли;
    
    Возврат 0;
    
КонецФункции

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

← На главную