Чтение реквизитов в коде 1С: точка, имя в строке, запрос и БСП
Содержание
Получить значение свойства объекта в 1С проще всего через точку: Контрагент.ИНН, Документ.Дата, Объект.Товары[0].Количество. Если имя свойства известно только во время выполнения, пишут Объект["ИНН"]. Для одной ссылки на сервере удобнее и надёжнее функция БСП ОбщегоНазначения.ЗначениеРеквизитаОбъекта(Ссылка, "ИНН"), а для сотни ссылок — один запрос.
Какой способ выбрать, зависит от трёх вещей: где выполняется код (клиент или сервер), что у вас в руках (ссылка, объект, данные формы, коллекция) и сколько значений нужно прочитать. Всё это ниже на примерах для платформы 8.3 и типовых конфигураций на БСП.
Как получить значение свойства через точку
Точечная нотация — базовый синтаксис встроенного языка. Слева значение, справа имя реквизита из метаданных или стандартного реквизита:
ИННКонтрагента = Контрагент.ИНН;
ДатаДокумента = ДокументСсылка.Дата;
Наименование = ЭлементСправочника.Наименование;
Точки можно выстраивать цепочкой. Платформа сама прочитает нужные данные по каждой ссылке:
// Документ → контрагент → головной контрагент → ИНН
ИНН = Реализация.Контрагент.ГоловнойКонтрагент.ИНН;
Ссылка и объект — в чём разница
Точка работает и со ссылкой (СправочникСсылка.Контрагенты), и с объектом (СправочникОбъект.Контрагенты). Но поведение разное:
| Что в переменной | Как читается свойство | Можно изменить значение |
|---|---|---|
| Ссылка | Платформа читает данные из базы при обращении | Нет |
Объект (ПолучитьОбъект()) | Из уже загруженного в память объекта | Да, затем Записать() |
Данные формы (Объект в форме) | Из реквизита формы, без обращения к базе | Да, в форме |
Если нужно только прочитать значение, объект через ПолучитьОбъект() получать не надо. Это лишняя загрузка всех реквизитов и табличных частей.
Стандартные реквизиты
Кроме реквизитов, добавленных разработчиком, у объектов есть стандартные. Их тоже читают через точку:
- 📘 справочники —
Код,Наименование,Родитель,Владелец,ПометкаУдаления,ЭтоГруппа; - 📄 документы —
Номер,Дата,Проведен,ПометкаУдаления; - 🔗 у всех ссылочных —
Ссылка.
Точное имя реквизита смотрите в Конфигураторе: дерево метаданных → объект → ветка «Реквизиты». Синоним, который виден пользователю на форме, в коде не работает.
Получение значения свойства по имени из строки
Иногда имя реквизита приходит из настроек, из файла обмена или из параметра функции. Тогда используют квадратные скобки:
ИмяРеквизита = "ИНН";
Значение = Контрагент[ИмяРеквизита];
Запись Контрагент["ИНН"] равнозначна Контрагент.ИНН. Скобки работают для ссылок, объектов, структур, строк табличных частей и таблиц значений, данных формы.
Перебор всех реквизитов объекта
Список имён берут из метаданных. Пример выводит все реквизиты элемента справочника:
МетаданныеОбъекта = Ссылка.Метаданные();
Для Каждого Реквизит Из МетаданныеОбъекта.Реквизиты Цикл
Сообщить(Реквизит.Имя + " = " + Строка(Ссылка[Реквизит.Имя]));
КонецЦикла;
Стандартные реквизиты в коллекции Реквизиты не входят. Для них есть отдельная коллекция СтандартныеРеквизиты.
Почему не Вычислить()
Старый приём Вычислить("Объект." + ИмяРеквизита) тоже вернёт значение. Но он медленнее, плохо читается и опасен: если имя приходит снаружи, в строку можно подсунуть произвольный код. В безопасном режиме и в ряде облачных сценариев такой вызов вообще запрещён.
Для доступа по имени используйте только квадратные скобки — без Вычислить() и Выполнить().
Значения свойств в коллекциях: табличные части, структуры, массивы
У каждой коллекции свой способ достать значение. Сводная таблица:
| Коллекция | Как получить значение | Пример |
|---|---|---|
| Табличная часть | Индекс строки + имя колонки | Документ.Товары[0].Номенклатура |
| Таблица значений | Так же, либо Найти() | Таблица[2].Сумма |
| Структура | Ключ через точку или Свойство() | Параметры.Организация |
| Соответствие | Получить() или скобки | Цены.Получить(Номенклатура) |
| Массив | Индекс с нуля | Массив[0] |
Табличная часть и таблица значений
Нумерация строк начинается с нуля. Последняя строка — Товары[Товары.Количество() - 1].
Чтобы собрать все значения одной колонки, не нужен цикл:
// Табличная часть документа
СписокНоменклатуры = ДокументОбъект.Товары.ВыгрузитьКолонку("Номенклатура");
// Сумма по колонке
ИтогоСумма = ДокументОбъект.Товары.Итог("Сумма");
Найти строку по значению поля помогают Найти() (первая подходящая) и НайтиСтроки() (все подходящие):
Отбор = Новый Структура("Номенклатура", ИскомыйТовар);
НайденныеСтроки = ДокументОбъект.Товары.НайтиСтроки(Отбор);
Для Каждого Строка Из НайденныеСтроки Цикл
Количество = Количество + Строка.Количество;
КонецЦикла;
Структура: безопасное чтение ключа
Если ключа в структуре нет, Параметры.Организация вызовет ошибку. Метод Свойство() проверяет ключ и сразу возвращает значение:
Организация = Неопределено;
Если Параметры.Свойство("Организация", Организация) Тогда
// ключ есть, значение уже в переменной Организация
КонецЕсли;
Метод возвращает Истина или Ложь, а второй параметр заполняет значением. Один вызов вместо двух.
Соответствие
У соответствия ключ может быть любого типа, поэтому точка не работает
. Получить() при отсутствии ключа возвращает Неопределено, без ошибки:
Цена = ЦеныНоменклатуры.Получить(Номенклатура);
Если Цена = Неопределено Тогда
Цена = 0;
КонецЕсли;
Как получить значение свойства в управляемой форме
В форме три разных сущности, которые легко перепутать:
- 🧾 Реквизит формы — данные. Основной обычно называется
Объект:Объект.Контрагент,Объект.Товары. - 🖱️ Элемент формы — поле на экране:
Элементы.Контрагент. У элемента есть свойстваВидимость,Доступность,Заголовок, но не значение данных. - 🧩 Произвольный реквизит формы — добавленный в редакторе формы. Читается по имени напрямую:
ВыбранныйПериод.
&НаКлиенте
Процедура ПроверитьКонтрагента(Команда)
Если Не ЗначениеЗаполнено(Объект.Контрагент) Тогда
Сообщить("Укажите контрагента");
КонецЕсли;
КонецПроцедуры
Реквизит ссылки на клиенте
Самое частое затруднение: на клиенте ссылка есть, а её реквизиты прочитать нельзя. Запись Объект.Контрагент.ИНН в процедуре &НаКлиенте не сработает, потому что клиент не обращается к базе напрямую.
Решение — серверная функция без контекста формы:
&НаКлиенте
Процедура КонтрагентПриИзменении(Элемент)
ИНН = ИННКонтрагента(Объект.Контрагент);
КонецПроцедуры
&НаСервереБезКонтекста
Функция ИННКонтрагента(Контрагент)
Возврат ОбщегоНазначения.ЗначениеРеквизитаОбъекта(Контрагент, "ИНН");
КонецФункции
&НаСервереБезКонтекста не передаёт на сервер всю форму, поэтому вызов лёгкий. &НаСервере здесь избыточен.
Текущая строка таблицы на форме
Значения выделенной строки берут через ТекущиеДанные элемента таблицы:
ТекущиеДанные = Элементы.Товары.ТекущиеДанные;
Если ТекущиеДанные = Неопределено Тогда
Возврат; // ни одна строка не выделена
КонецЕсли;
Номенклатура = ТекущиеДанные.Номенклатура;
Проверка на Неопределено обязательна: пустая таблица или снятое выделение дадут ошибку на следующей строке.
Динамически добавленные реквизиты формы
Если реквизит формы создан программно через ИзменитьРеквизиты(), его имя в коде заранее неизвестно. Читайте его скобками от самой формы: ЭтотОбъект[ИмяРеквизита].
Чтобы на сервере работать с объектом формы как с прикладным объектом (вызывать его методы из модуля объекта), используйте РеквизитФормыВЗначение("Объект"). Для простого чтения значений это не нужно.
Если свойства нет: проверка и обработка ошибок
Обращение к несуществующему реквизиту даёт ошибку времени выполнения Поле объекта не обнаружено (ИмяРеквизита). Если переменная содержит Неопределено вместо ссылки, сообщение другое: Значение не является значением объектного типа (ИмяРеквизита).
Проверка через метаданные
Для ссылочных объектов надёжный способ — искать реквизит в метаданных:
Функция ЕстьРеквизит(Значение, ИмяРеквизита)
МД = Значение.Метаданные();
Возврат МД.Реквизиты.Найти(ИмяРеквизита) <> Неопределено
Или МД.СтандартныеРеквизиты.Найти(ИмяРеквизита) <> Неопределено;
КонецФункции
Универсальная проверка через ЗаполнитьЗначенияСвойств
Этот приём подходит для любых значений, включая данные формы и строки таблиц. В структуру кладут ключ с уникальной меткой и пробуют заполнить её из источника. Если метка осталась — свойства нет:
Функция ЗначениеСвойстваИлиУмолчание(Источник, ИмяСвойства, ПоУмолчанию = Неопределено)
Метка = Новый УникальныйИдентификатор;
Приемник = Новый Структура(ИмяСвойства, Метка);
ЗаполнитьЗначенияСвойств(Приемник, Источник);
Если Приемник[ИмяСвойства] = Метка Тогда
Возврат ПоУмолчанию;
КонецЕсли;
Возврат Приемник[ИмяСвойства];
КонецФункции
Метка нужна, чтобы отличить «свойства нет» от «свойство есть, но пустое или Неопределено».
Попытка…Исключение
Перехват ошибки допустим, но как последний рубеж, а не основной способ проверки:
Попытка
Значение = Источник[ИмяСвойства];
Исключение
ЗаписьЖурналаРегистрации("Чтение свойства", УровеньЖурналаРегистрации.Ошибка,,,
ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
Значение = Неопределено;
КонецПопытки;
Составной тип и пустые ссылки
Если реквизит составного типа (например, «Контрагент» может быть контрагентом или физлицом), перед чтением вложенного свойства проверьте тип:
Если ТипЗнч(Документ.Контрагент) = Тип("СправочникСсылка.Контрагенты") Тогда
ИНН = Документ.Контрагент.ИНН;
КонецЕсли;
Пустую ссылку проверяют через ЗначениеЗаполнено(). Обращение к реквизитам пустой ссылки ошибки не даёт, но вернёт пустые значения — и код молча продолжит работу с пустым ИНН.
Дополнительные реквизиты: когда «свойство» хранится не в метаданных
В типовых конфигурациях на БСП пользователь сам добавляет поля через дополнительные реквизиты и сведения. В Конфигураторе их не видно, и Контрагент.МоеПоле не сработает.
Дополнительные реквизиты хранятся в табличной части объекта ДополнительныеРеквизиты с колонками Свойство и Значение. Само свойство — элемент плана видов характеристик ДополнительныеРеквизитыИДополнительныеСведения. Прочитать значение можно запросом:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ДопРеквизиты.Значение КАК Значение
|ИЗ
| Справочник.Контрагенты.ДополнительныеРеквизиты КАК ДопРеквизиты
|ГДЕ
| ДопРеквизиты.Ссылка = &Ссылка
| И ДопРеквизиты.Свойство = &Свойство";
Запрос.УстановитьПараметр("Ссылка", Контрагент);
Запрос.УстановитьПараметр("Свойство", СвойствоСсылка);
Выборка = Запрос.Выполнить().Выбрать();
Значение = ?(Выборка.Следующий(), Выборка.Значение, Неопределено);
Дополнительные сведения лежат не в объекте, а в регистре сведений ДополнительныеСведения с измерениями Объект и Свойство. Запрос строится так же, только источник — регистр.
Свойство в параметре запроса — это ссылка на элемент плана видов характеристик, а не строка с названием. Найдите элемент по наименованию заранее или храните его ссылку в настройках.
Быстродействие: как читать значения реквизитов без лишних запросов
Каждое обращение через точку от ссылки — это чтение из базы. В одной строке кода это незаметно. В цикле по 5 000 документов получается 5 000 обращений к базе, а с цепочкой Документ.Контрагент.ИНН — вдвое больше.
Одна ссылка — функции БСП
В конфигурациях на БСП есть готовые функции общего модуля ОбщегоНазначения:
| Задача | Функция | Что вернёт |
|---|---|---|
| Один реквизит одной ссылки | ЗначениеРеквизитаОбъекта(Ссылка, "ИНН") | Значение |
| Несколько реквизитов одной ссылки | ЗначенияРеквизитовОбъекта(Ссылка, "ИНН, КПП") | Структура |
| Один реквизит многих ссылок | ЗначениеРеквизитаОбъектов(МассивСсылок, "ИНН") | Соответствие «ссылка → значение» |
| Несколько реквизитов многих ссылок | ЗначенияРеквизитовОбъектов(МассивСсылок, "ИНН, КПП") | Соответствие «ссылка → структура» |
Функции читают только нужные поля одним запросом, а не весь объект. Работают на сервере.
Реквизиты = ОбщегоНазначения.ЗначенияРеквизитовОбъекта(Контрагент, "ИНН, КПП, Наименование");
Сообщить(Реквизиты.Наименование + ", ИНН " + Реквизиты.ИНН);
Много ссылок — запрос вместо цикла с точками
Плохо — по обращению к базе на каждой итерации:
Для Каждого Док Из МассивДокументов Цикл
ИНН = Док.Контрагент.ИНН;
// ...
КонецЦикла;
Хорошо — одним запросом все нужные поля:
Запрос = Новый Запрос(
"ВЫБРАТЬ
| Док.Ссылка КАК Документ,
| Док.Контрагент.ИНН КАК ИНН
|ИЗ
| Документ.РеализацияТоваровУслуг КАК Док
|ГДЕ
| Док.Ссылка В (&Документы)");
Запрос.УстановитьПараметр("Документы", МассивДокументов);
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
// Выборка.Документ, Выборка.ИНН
КонецЦикла;
Разыменование Док.Контрагент.ИНН внутри запроса платформа превращает в соединение таблиц. Это на порядки быстрее цикла.
Короткие правила
- ⚡ Читать значение — по ссылке, а не через
ПолучитьОбъект(). - 🔁 В цикле не ходить через точку от ссылки: собрать массив и выполнить один запрос.
- 💾 Значение, нужное несколько раз, сохранить в переменную, а не разыменовывать заново.
- 🧭 На клиенте — один серверный вызов на все нужные реквизиты, а не по вызову на каждый.
- 🧱 Для составных типов в запросе использовать
ВЫРАЗИТЬ(Поле КАК Справочник.Контрагенты), чтобы платформа не соединяла все возможные таблицы.
Частые вопросы
Как получить представление ссылки, а не саму ссылку?
Строка(Ссылка) вернёт представление — обычно наименование или номер с датой. В запросе для этого есть ПРЕДСТАВЛЕНИЕ(Поле).Можно ли изменить значение свойства через ссылку?
ПолучитьОбъект(), присвойте значение и вызовите Записать().Как узнать тип значения реквизита?
ТипЗнч(Значение) вернёт тип конкретного значения. Описание допустимых типов реквизита — в метаданных: Значение.Метаданные().Реквизиты.ИмяРеквизита.Тип.Как скопировать значения одноимённых свойств из одного объекта в другой?
ЗаполнитьЗначенияСвойств(Приемник, Источник) переносит все совпадающие по имени свойства. Третьим и четвёртым параметрами задают список нужных или исключаемых свойств через запятую.