Чтение реквизитов в коде 1С: точка, имя в строке, запрос и БСП

· 9 мин

Содержание

Получить значение свойства объекта в 1С проще всего через точку: Контрагент.ИНН, Документ.Дата, Объект.Товары[0].Количество. Если имя свойства известно только во время выполнения, пишут Объект["ИНН"]. Для одной ссылки на сервере удобнее и надёжнее функция БСП ОбщегоНазначения.ЗначениеРеквизитаОбъекта(Ссылка, "ИНН"), а для сотни ссылок — один запрос.

Какой способ выбрать, зависит от трёх вещей: где выполняется код (клиент или сервер), что у вас в руках (ссылка, объект, данные формы, коллекция) и сколько значений нужно прочитать. Всё это ниже на примерах для платформы 8.3 и типовых конфигураций на БСП.

Как получить значение свойства через точку

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

ИННКонтрагента = Контрагент.ИНН;
ДатаДокумента  = ДокументСсылка.Дата;
Наименование   = ЭлементСправочника.Наименование;

Точки можно выстраивать цепочкой. Платформа сама прочитает нужные данные по каждой ссылке:

// Документ → контрагент → головной контрагент → ИНН
ИНН = Реализация.Контрагент.ГоловнойКонтрагент.ИНН;

Ссылка и объект — в чём разница

Точка работает и со ссылкой (СправочникСсылка.Контрагенты), и с объектом (СправочникОбъект.Контрагенты). Но поведение разное:

Что в переменнойКак читается свойствоМожно изменить значение
СсылкаПлатформа читает данные из базы при обращенииНет
Объект (ПолучитьОбъект())Из уже загруженного в память объектаДа, затем Записать()
Данные формы (Объект в форме)Из реквизита формы, без обращения к базеДа, в форме

Если нужно только прочитать значение, объект через ПолучитьОбъект() получать не надо. Это лишняя загрузка всех реквизитов и табличных частей.

Стандартные реквизиты

Кроме реквизитов, добавленных разработчиком, у объектов есть стандартные. Их тоже читают через точку:

  • 📘 справочники — Код, Наименование, Родитель, Владелец, ПометкаУдаления, ЭтоГруппа;
  • 📄 документы — Номер, Дата, Проведен, ПометкаУдаления;
  • 🔗 у всех ссылочных — Ссылка.

Точное имя реквизита смотрите в Конфигураторе: дерево метаданных → объект → ветка «Реквизиты». Синоним, который виден пользователю на форме, в коде не работает.

Получение значения свойства по имени из строки

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

ИмяРеквизита = "ИНН";
Значение = Контрагент[ИмяРеквизита];

Запись Контрагент["ИНН"] равнозначна Контрагент.ИНН. Скобки работают для ссылок, объектов, структур, строк табличных частей и таблиц значений, данных формы.

Перебор всех реквизитов объекта

Список имён берут из метаданных. Пример выводит все реквизиты элемента справочника:

МетаданныеОбъекта = Ссылка.Метаданные();
Для Каждого Реквизит Из МетаданныеОбъекта.Реквизиты Цикл
    Сообщить(Реквизит.Имя + " = " + Строка(Ссылка[Реквизит.Имя]));
КонецЦикла;

Стандартные реквизиты в коллекции Реквизиты не входят. Для них есть отдельная коллекция СтандартныеРеквизиты.

Почему не Вычислить()

Старый приём Вычислить("Объект." + ИмяРеквизита) тоже вернёт значение. Но он медленнее, плохо читается и опасен: если имя приходит снаружи, в строку можно подсунуть произвольный код. В безопасном режиме и в ряде облачных сценариев такой вызов вообще запрещён.

Для доступа по имени используйте только квадратные скобки — без Вычислить() и Выполнить().

Значения свойств в коллекциях: табличные части, структуры, массивы

У каждой коллекции свой способ достать значение. Сводная таблица:

КоллекцияКак получить значениеПример
Табличная частьИндекс строки + имя колонкиДокумент.Товары[0].Номенклатура
Таблица значенийТак же, либо Найти()Таблица[2].Сумма
СтруктураКлюч через точку или Свойство()Параметры.Организация
СоответствиеПолучить() или скобкиЦены.Получить(Номенклатура)
МассивИндекс с нуляМассив[0]

Табличная часть и таблица значений

Нумерация строк начинается с нуля. Последняя строка — Товары[Товары.Количество() - 1].

Чтобы собрать все значения одной колонки, не нужен цикл:

// Табличная часть документа
СписокНоменклатуры = ДокументОбъект.Товары.ВыгрузитьКолонку("Номенклатура");

// Сумма по колонке
ИтогоСумма = ДокументОбъект.Товары.Итог("Сумма");

Найти строку по значению поля помогают Найти() (первая подходящая) и НайтиСтроки() (все подходящие):

Отбор = Новый Структура("Номенклатура", ИскомыйТовар);
НайденныеСтроки = ДокументОбъект.Товары.НайтиСтроки(Отбор);
Для Каждого Строка Из НайденныеСтроки Цикл
    Количество = Количество + Строка.Количество;
КонецЦикла;

Структура: безопасное чтение ключа

Если ключа в структуре нет, Параметры.Организация вызовет ошибку. Метод Свойство() проверяет ключ и сразу возвращает значение:

Организация = Неопределено;
Если Параметры.Свойство("Организация", Организация) Тогда
    // ключ есть, значение уже в переменной Организация
КонецЕсли;

Метод возвращает Истина или Ложь, а второй параметр заполняет значением. Один вызов вместо двух.

Соответствие

У соответствия ключ может быть любого типа, поэтому точка не работает . Получить() при отсутствии ключа возвращает Неопределено, без ошибки:

Цена = ЦеныНоменклатуры.Получить(Номенклатура);
Если Цена = Неопределено Тогда
    Цена = 0;
КонецЕсли;

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

В форме три разных сущности, которые легко перепутать:

  • 🧾 Реквизит формы — данные. Основной обычно называется Объект: Объект.Контрагент, Объект.Товары.
  • 🖱️ Элемент формы — поле на экране: Элементы.Контрагент. У элемента есть свойства Видимость, Доступность, Заголовок, но не значение данных.
  • 🧩 Произвольный реквизит формы — добавленный в редакторе формы. Читается по имени напрямую: ВыбранныйПериод.
&НаКлиенте
Процедура ПроверитьКонтрагента(Команда)
    Если Не ЗначениеЗаполнено(Объект.Контрагент) Тогда
        Сообщить("Укажите контрагента");
    КонецЕсли;
КонецПроцедуры

Реквизит ссылки на клиенте

Самое частое затруднение: на клиенте ссылка есть, а её реквизиты прочитать нельзя. Запись Объект.Контрагент.ИНН в процедуре &НаКлиенте не сработает, потому что клиент не обращается к базе напрямую.

Решение — серверная функция без контекста формы:

&НаКлиенте
Процедура КонтрагентПриИзменении(Элемент)
    ИНН = ИННКонтрагента(Объект.Контрагент);
КонецПроцедуры

&НаСервереБезКонтекста
Функция ИННКонтрагента(Контрагент)
    Возврат ОбщегоНазначения.ЗначениеРеквизитаОбъекта(Контрагент, "ИНН");
КонецФункции

&НаСервереБезКонтекста не передаёт на сервер всю форму, поэтому вызов лёгкий. &НаСервере здесь избыточен.

Текущая строка таблицы на форме

Значения выделенной строки берут через ТекущиеДанные элемента таблицы:

ТекущиеДанные = Элементы.Товары.ТекущиеДанные;
Если ТекущиеДанные = Неопределено Тогда
    Возврат; // ни одна строка не выделена
КонецЕсли;
Номенклатура = ТекущиеДанные.Номенклатура;

Проверка на Неопределено обязательна: пустая таблица или снятое выделение дадут ошибку на следующей строке.

Динамически добавленные реквизиты формы

Если реквизит формы создан программно через ИзменитьРеквизиты(), его имя в коде заранее неизвестно. Читайте его скобками от самой формы: ЭтотОбъект[ИмяРеквизита].

Чтобы на сервере работать с объектом формы как с прикладным объектом (вызывать его методы из модуля объекта), используйте РеквизитФормыВЗначение("Объект"). Для простого чтения значений это не нужно.

Если свойства нет: проверка и обработка ошибок

Обращение к несуществующему реквизиту даёт ошибку времени выполнения Поле объекта не обнаружено (ИмяРеквизита). Если переменная содержит Неопределено вместо ссылки, сообщение другое: Значение не является значением объектного типа (ИмяРеквизита).

Проверка через метаданные

Для ссылочных объектов надёжный способ — искать реквизит в метаданных:

Функция ЕстьРеквизит(Значение, ИмяРеквизита)
    МД = Значение.Метаданные();
    Возврат МД.Реквизиты.Найти(ИмяРеквизита) <> Неопределено
        Или МД.СтандартныеРеквизиты.Найти(ИмяРеквизита) <> Неопределено;
КонецФункции

Универсальная проверка через ЗаполнитьЗначенияСвойств

Этот приём подходит для любых значений, включая данные формы и строки таблиц. В структуру кладут ключ с уникальной меткой и пробуют заполнить её из источника. Если метка осталась — свойства нет:

Функция ЗначениеСвойстваИлиУмолчание(Источник, ИмяСвойства, ПоУмолчанию = Неопределено)
    Метка = Новый УникальныйИдентификатор;
    Приемник = Новый Структура(ИмяСвойства, Метка);
    ЗаполнитьЗначенияСвойств(Приемник, Источник);
    Если Приемник[ИмяСвойства] = Метка Тогда
        Возврат ПоУмолчанию;
    КонецЕсли;
    Возврат Приемник[ИмяСвойства];
КонецФункции

Метка нужна, чтобы отличить «свойства нет» от «свойство есть, но пустое или Неопределено».

Попытка…Исключение

Перехват ошибки допустим, но как последний рубеж, а не основной способ проверки:

Попытка
    Значение = Источник[ИмяСвойства];
Исключение
    ЗаписьЖурналаРегистрации("Чтение свойства", УровеньЖурналаРегистрации.Ошибка,,,
        ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
    Значение = Неопределено;
КонецПопытки;

Составной тип и пустые ссылки

Если реквизит составного типа (например, «Контрагент» может быть контрагентом или физлицом), перед чтением вложенного свойства проверьте тип:

Если ТипЗнч(Документ.Контрагент) = Тип("СправочникСсылка.Контрагенты") Тогда
    ИНН = Документ.Контрагент.ИНН;
КонецЕсли;

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

Диагностика: выберите симптом

Дополнительные реквизиты: когда «свойство» хранится не в метаданных

В типовых конфигурациях на БСП пользователь сам добавляет поля через дополнительные реквизиты и сведения. В Конфигураторе их не видно, и Контрагент.МоеПоле не сработает.

Дополнительные реквизиты хранятся в табличной части объекта ДополнительныеРеквизиты с колонками Свойство и Значение. Само свойство — элемент плана видов характеристик ДополнительныеРеквизитыИДополнительныеСведения. Прочитать значение можно запросом:

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

Выборка = Запрос.Выполнить().Выбрать();
Значение = ?(Выборка.Следующий(), Выборка.Значение, Неопределено);

Дополнительные сведения лежат не в объекте, а в регистре сведений ДополнительныеСведения с измерениями Объект и Свойство. Запрос строится так же, только источник — регистр.

Свойство в параметре запроса — это ссылка на элемент плана видов характеристик, а не строка с названием. Найдите элемент по наименованию заранее или храните его ссылку в настройках.

Быстродействие: как читать значения реквизитов без лишних запросов

Каждое обращение через точку от ссылки — это чтение из базы. В одной строке кода это незаметно. В цикле по 5 000 документов получается 5 000 обращений к базе, а с цепочкой Документ.Контрагент.ИНН — вдвое больше.

Одна ссылка — функции БСП

В конфигурациях на БСП есть готовые функции общего модуля ОбщегоНазначения:

ЗадачаФункцияЧто вернёт
Один реквизит одной ссылкиЗначениеРеквизитаОбъекта(Ссылка, "ИНН")Значение
Несколько реквизитов одной ссылкиЗначенияРеквизитовОбъекта(Ссылка, "ИНН, КПП")Структура
Один реквизит многих ссылокЗначениеРеквизитаОбъектов(МассивСсылок, "ИНН")Соответствие «ссылка → значение»
Несколько реквизитов многих ссылокЗначенияРеквизитовОбъектов(МассивСсылок, "ИНН, КПП")Соответствие «ссылка → структура»

Функции читают только нужные поля одним запросом, а не весь объект. Работают на сервере.

Реквизиты = ОбщегоНазначения.ЗначенияРеквизитовОбъекта(Контрагент, "ИНН, КПП, Наименование");
Сообщить(Реквизиты.Наименование + ", ИНН " + Реквизиты.ИНН);

Много ссылок — запрос вместо цикла с точками

Плохо — по обращению к базе на каждой итерации:

Для Каждого Док Из МассивДокументов Цикл
    ИНН = Док.Контрагент.ИНН;
    // ...
КонецЦикла;

Хорошо — одним запросом все нужные поля:

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

Разыменование Док.Контрагент.ИНН внутри запроса платформа превращает в соединение таблиц. Это на порядки быстрее цикла.

Короткие правила

  • ⚡ Читать значение — по ссылке, а не через ПолучитьОбъект().
  • 🔁 В цикле не ходить через точку от ссылки: собрать массив и выполнить один запрос.
  • 💾 Значение, нужное несколько раз, сохранить в переменную, а не разыменовывать заново.
  • 🧭 На клиенте — один серверный вызов на все нужные реквизиты, а не по вызову на каждый.
  • 🧱 Для составных типов в запросе использовать ВЫРАЗИТЬ(Поле КАК Справочник.Контрагенты), чтобы платформа не соединяла все возможные таблицы.

Частые вопросы

Как получить представление ссылки, а не саму ссылку?
Функция Строка(Ссылка) вернёт представление — обычно наименование или номер с датой. В запросе для этого есть ПРЕДСТАВЛЕНИЕ(Поле).
Можно ли изменить значение свойства через ссылку?
Нет. Ссылка доступна только для чтения. Получите объект через ПолучитьОбъект(), присвойте значение и вызовите Записать().
Как узнать тип значения реквизита?
ТипЗнч(Значение) вернёт тип конкретного значения. Описание допустимых типов реквизита — в метаданных: Значение.Метаданные().Реквизиты.ИмяРеквизита.Тип.
Как скопировать значения одноимённых свойств из одного объекта в другой?
Процедура ЗаполнитьЗначенияСвойств(Приемник, Источник) переносит все совпадающие по имени свойства. Третьим и четвёртым параметрами задают список нужных или исключаемых свойств через запятую.
Работает ли ЗначениеРеквизитаОбъекта без БСП?
Нет, это функция библиотеки стандартных подсистем. В самописной конфигурации без БСП пишите короткий запрос к таблице объекта с отбором по ссылке.