Как прочитать и записать реквизит объекта в коде расширения 1С
Содержание
Реквизит основной конфигурации в расширении доступен только после заимствования объекта. Реквизит, который добавило само расширение, виден только внутри этого расширения. Из этих двух правил вытекает почти всё, что ломается у разработчиков при первой попытке обратиться к реквизиту из расширения 1С.
Ниже порядок действий: что заимствовать, как читать и писать данные в модуле объекта и формы, как вывести реквизит в запросе и динамическом списке, и какие ошибки вылетают чаще всего.
С чего начать: два вида реквизитов в расширении
В коде расширения вы работаете с реквизитами двух видов. Способ обращения один и тот же (Объект.ИмяРеквизита), а вот условия доступа разные.
| Вид | Откуда | Что нужно сделать |
|---|---|---|
| Заимствованный | Есть в основной конфигурации | Заимствовать объект в расширение |
| Собственный | Добавлен в расширении | Ничего, он создан внутри расширения |
Что важно помнить:
- 🔹 Заимствуется не весь объект целиком, а нужные части. При заимствовании объекта в расширении появляется «тень» с его реквизитами, формами и модулями.
- 🔹 Основная конфигурация о собственных реквизитах расширения ничего не знает. Её код на них не ссылается и в синтаксической проверке их не видит.
- 🔹 Имена собственных объектов расширения принято начинать с префикса (например,
мр_). Так они не пересекутся с будущими объектами поставщика.
Расширение подключается к конфигурации с флагом «Изменяет и дополняет конфигурацию». Если расширение не применяется, ни один из способов ниже не заработает: код просто не выполнится.
Заимствование объекта: без него реквизит не виден
Откройте конфигурацию в конфигураторе, перейдите в расширение и добавьте в него нужный объект командой заимствования из основной конфигурации. Для справочника, документа или регистра сделайте это один раз.
Порядок такой:
- Откройте основную конфигурацию и найдите объект, например справочник «Номенклатура».
- Выберите команду добавления объекта в расширение (через контекстное меню).
- Убедитесь, что объект появился в дереве расширения со значком заимствованного.
- Раскройте его: реквизиты, табличные части и формы отображаются в виде «тени».
Дальше у вас есть два пути. Если нужно только прочитать реквизит, заимствуйте объект и пишите код. Если нужно изменить поведение стандартной процедуры, заимствуйте ещё и модуль, а затем перехватывайте метод директивами.
Заимствование не копирует данные и не меняет основную конфигурацию. Оно только открывает расширению доступ к описанию объекта.
Обращение к реквизитам документов и справочников
Модуль объекта
В расширении модуль заимствованного объекта содержит только процедуры, которые вы перехватываете. Обращение к реквизитам идёт как в обычном коде, через ЭтотОбъект:
&После("ПередЗаписью")
Процедура мр_ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
Если ЭтотОбъект.мр_ПроверятьКонтрагента Тогда
Если Не ЗначениеЗаполнено(ЭтотОбъект.Контрагент) Тогда
Сообщить("Не заполнен контрагент");
Отказ = Истина;
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Здесь Контрагент взят из основной конфигурации, а мр_ПроверятьКонтрагента добавлен самим расширением. В коде они выглядят одинаково.
Какую директиву выбрать:
&Перед— выполнить свой код до штатной процедуры;&После— после неё;&Вместо— заменить штатный код, при этом вызвать оригинал можно черезПродолжитьВызов();&ИзменениеИКонтроль— править кусок штатного кода с контролем изменений при обновлении.
Директива &Вместо ломает цепочку обновлений: если поставщик изменит процедуру, ваша замена продолжит работать по старой логике. Начинайте с &После и &Перед.
Ссылка на объект
Если у вас на руках только ссылка, прочитайте реквизит через неё. Для одного значения это самый короткий путь:
ДатаДоговора = ОбщегоНазначения.ЗначениеРеквизитаОбъекта(Договор, "Дата");
Пример использует типовую подсистему стандартных подсистем (БСП), которая есть не во всех конфигурациях. Без неё придётся использовать запрос или обращение Договор.Дата: последнее читает весь объект, поэтому для списка ссылок оно медленнее запроса.
Реквизиты табличных частей
Табличная часть читается так же: Для Каждого Строка Из ЭтотОбъект.Товары Цикл. Реквизит расширения в строке получает значение как обычное поле строки. Если табличную часть добавило расширение, её нужно искать в собственных объектах расширения.
Предопределённые элементы и константы
Предопределённый элемент заимствованного справочника доступен обычным путём:
ВидЦены = Справочники.ВидыЦен.Оптовая;
Если ту же «Оптовую» добавили в расширении, обращение выглядит так же, но работает, только пока расширение подключено. Без него в базе остаётся ссылка, которая не разворачивается в имя.
Константа читается и пишется через менеджер:
ТекущееЗначение = Константы.мр_ЛимитОтгрузки.Получить();
Константы.мр_ЛимитОтгрузки.Установить(5000);
Что здесь стоит знать:
- 🔹 Константы основной конфигурации после заимствования читаются из расширения тем же кодом.
- 🔹 Константа, созданная расширением, при отключении расширения теряет доступ: данные в таблицах остаются, но платформа их не показывает.
- 🔹 Права на чтение и запись константы выдаются ролями. Роль расширения нужно назначить пользователю отдельно.
Регистры сведений и накопления
Для регистра сведений основной конфигурации заимствуйте регистр и работайте через менеджер записи:
Запись = РегистрыСведений.мр_ЛимитыКонтрагентов.СоздатьМенеджерЗаписи();
Запись.Контрагент = Контрагент;
Запись.Прочитать();
Если Запись.Выбран() Тогда
Лимит = Запись.Лимит;
КонецЕсли;
Для накопления проще всего построить запрос к виртуальной таблице остатков. Перебирать записи в цикле не нужно, это дорого по времени.
Практические ориентиры:
| Задача | Инструмент |
|---|---|
| Одно значение по ключу | Менеджер записи регистра сведений |
| Остатки, обороты | Виртуальные таблицы в запросе |
| Массовая запись | Набор записей регистра (СоздатьНаборЗаписей) |
Поля, которые добавило расширение, доступны в запросе под своим именем. Если регистр заимствован, но нужное поле создано в расширении, при открытии конфигурации основной конфигурации оно не отобразится.
Реквизит в форме и динамическом списке
Реквизит на форму выводится двумя способами: перетаскиванием в дереве формы и программным созданием элементов.
Для заимствованной формы:
- Откройте форму объекта в расширении (она заимствуется отдельно).
- Перетащите реквизит объекта на форму. Для собственного реквизита расширения он доступен в списке «Объект».
- Перенесите расположение и задайте заголовок.
- Обработчики событий добавляйте через перехват процедур формы.
Если нужно создать элемент из кода, используйте Элементы.Добавить, а реквизит формы добавьте через ИзменитьРеквизиты:
&НаСервере
&После("ПриСозданииНаСервере")
Процедура мр_ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
Реквизиты = Новый Массив;
Реквизиты.Добавить(Новый РеквизитФормы("мр_Примечание", Новый ОписаниеТипов("Строка")));
ИзменитьРеквизиты(Реквизиты);
КонецПроцедуры
Динамический список
В форме списка поля берутся из основной таблицы. Чтобы добавить собственное поле:
- включите «Произвольный запрос» у динамического списка и добавьте поле в текст запроса;
- либо откройте настройку списка и подключите реквизит расширения как поле основной таблицы, если тип списка это допускает.
Если после обновления поле пропало, посмотрите, не изменил ли поставщик текст запроса списка. В таком случае повторите правку на новом запросе.
Запросы, типы и запись реквизитов расширения
Запрос к реквизиту
Реквизит расширения в запросе пишется так же, как и любой другой: через точку после имени таблицы или ссылки.
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Номенклатура.Ссылка КАК Ссылка,
| Номенклатура.мр_СрокГодности КАК СрокГодности
|ИЗ
| Справочник.Номенклатура КАК Номенклатура
|ГДЕ
| Номенклатура.мр_СрокГодности > 0";
Выборка = Запрос.Выполнить().Выбрать();
Что стоит учесть:
- 🔹 Запрос с реквизитом расширения работает, только пока расширение подключено. Если расширение отключат, запрос выдаст ошибку компиляции.
- 🔹 Через точку по ссылке (
Номенклатура.Ссылка.мр_СрокГодности) можно ходить на несколько уровней, но каждое соединение замедляет выборку. Для больших таблиц лучше вывести значение отдельным полем. - 🔹 Реквизит расширения можно использовать в условиях, группировках и сортировках так же, как и штатный.
Отбор и сортировка по реквизиту в списке
Чтобы пользователь мог отбирать список по собственному реквизиту, достаточно добавить поле в запрос динамического списка. После этого оно появится в настройке отборов и сортировки формы. Если поле не видно, проверьте, не отключена ли у списка возможность пользовательской настройки.
Типы реквизитов: на что обратить внимание
Тип реквизита влияет на то, как с ним безопасно работать. Особенно это важно для ссылок на объекты расширения.
| Тип | Особенность в расширении |
|---|---|
| Строка, число, дата, булево | Работает без ограничений |
| Ссылка на объект основной конфигурации | Объект должен быть заимствован |
| Ссылка на объект расширения | Значение обнуляется, если расширение отключить |
| Определяемый тип | Расширение может дополнить состав типов |
| Хранилище значения | Читайте через Получить(), пишите через Новый ХранилищеЗначения |
Не храните в реквизите расширения ссылки на объекты, которые создаёт то же расширение, если планируете когда-нибудь его отключать. Такие значения превратятся в пустые ссылки.
Для хранилища значения пример выглядит так:
Значение = ЭтотОбъект.мр_Данные.Получить();
ЭтотОбъект.мр_Данные = Новый ХранилищеЗначения(НовоеЗначение, Новый СжатиеДанных(9));
Запись реквизита и контроль изменений
Читать значение проще, чем записывать. При записи в реквизит из расширения нужно помнить про три вещи.
- Запись идёт через объект: получили объект (
Ссылка.ПолучитьОбъект()), изменили, вызвалиЗаписать(). Блокировка объекта на время изменения снижает риск конфликтов. - Если реквизит заимствованный и «только для чтения» в штатной логике, изменение лучше делать в обработчике
&После("ПередЗаписью"), а не перед открытием формы. - Для массовых изменений используйте обработки по списку объектов, а не цикл в обработчике формы: так проще откатить результат.
Пример безопасной записи:
Объект = Справочники.Номенклатура.НайтиПоКоду("00-000123").ПолучитьОбъект();
Объект.мр_СрокГодности = 365;
Объект.Записать();
Перед массовым изменением реквизитов выгрузите затронутые данные в файл или сделайте копию базы. Откатить пакетную запись без резервной копии трудно.
Ещё одна деталь касается обновлений. При переходе на новый релиз типовой конфигурации платформа сверяет заимствованные объекты с основной конфигурацией. Если поставщик удалил или переименовал реквизит, в расширении появляется расхождение, и его нужно разобрать вручную: открыть заимствованный объект, посмотреть сообщения о несоответствии и поправить обращения в коде. Чем меньше заимствованных объектов и перехваченных процедур, тем короче эта работа. Поэтому держите расширение небольшим и выносите бизнес-логику в собственные общие модули: они от обновлений не зависят, а в перехватах остаются только короткие вызовы.
Типичные ошибки и отладка
Сообщения платформы меняются от версии к версии, поэтому ищите причину по симптому.
| Симптом | Причина | Что делать |
|---|---|---|
| Поле объекта не найдено | Реквизит не заимствован или расширение не применено | Заимствуйте объект, примените расширение |
| В основной конфигурации код не компилируется | Ссылка на реквизит, существующий только в расширении | Уберите ссылку, вынесите логику в расширение |
| Реквизит на форме пустой | Реквизит не привязан к данным формы | Проверьте путь к данным реквизита |
| После обновления код не работает | Поставщик изменил процедуру или форму | Сверьте заимствованные объекты с новой версией |
Что проверить по порядку:
- Расширение подключено и «Изменяет и дополняет конфигурацию» включён.
- Объект заимствован, а не просто упомянут в коде.
- Код выполняется в нужном контексте: реквизит читается на сервере, а на клиенте он доступен только через данные формы.
Отладка идёт как обычно. Расширение можно отлаживать при запуске конфигуратора в режиме отладки, а затем остановиться на нужной строке. Если расширения не видны отладчику, проверьте, что они применены в той базе, которую вы отлаживаете.
Прежде чем править рабочую базу, сделайте резервную копию и обкатайте расширение на копии.
Частые вопросы
Можно ли из основной конфигурации обратиться к реквизиту расширения?
Нужно ли заимствовать объект, чтобы только читать его реквизит?
Что будет с данными реквизита, если расширение отключить?
Чем отличается &Вместо от &После?
&Вместо заменяет штатную процедуру, &После только дополняет её. Первый вариант рискованнее при обновлении типовой конфигурации.