Как прочитать и записать реквизит объекта в коде расширения 1С

· 9 мин

Содержание

Реквизит основной конфигурации в расширении доступен только после заимствования объекта. Реквизит, который добавило само расширение, виден только внутри этого расширения. Из этих двух правил вытекает почти всё, что ломается у разработчиков при первой попытке обратиться к реквизиту из расширения 1С.

Ниже порядок действий: что заимствовать, как читать и писать данные в модуле объекта и формы, как вывести реквизит в запросе и динамическом списке, и какие ошибки вылетают чаще всего.

С чего начать: два вида реквизитов в расширении

В коде расширения вы работаете с реквизитами двух видов. Способ обращения один и тот же (Объект.ИмяРеквизита), а вот условия доступа разные.

ВидОткудаЧто нужно сделать
ЗаимствованныйЕсть в основной конфигурацииЗаимствовать объект в расширение
СобственныйДобавлен в расширенииНичего, он создан внутри расширения

Что важно помнить:

  • 🔹 Заимствуется не весь объект целиком, а нужные части. При заимствовании объекта в расширении появляется «тень» с его реквизитами, формами и модулями.
  • 🔹 Основная конфигурация о собственных реквизитах расширения ничего не знает. Её код на них не ссылается и в синтаксической проверке их не видит.
  • 🔹 Имена собственных объектов расширения принято начинать с префикса (например, мр_). Так они не пересекутся с будущими объектами поставщика.

Расширение подключается к конфигурации с флагом «Изменяет и дополняет конфигурацию». Если расширение не применяется, ни один из способов ниже не заработает: код просто не выполнится.

Заимствование объекта: без него реквизит не виден

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

Порядок такой:

  1. Откройте основную конфигурацию и найдите объект, например справочник «Номенклатура».
  2. Выберите команду добавления объекта в расширение (через контекстное меню).
  3. Убедитесь, что объект появился в дереве расширения со значком заимствованного.
  4. Раскройте его: реквизиты, табличные части и формы отображаются в виде «тени».

Дальше у вас есть два пути. Если нужно только прочитать реквизит, заимствуйте объект и пишите код. Если нужно изменить поведение стандартной процедуры, заимствуйте ещё и модуль, а затем перехватывайте метод директивами.

Заимствование не копирует данные и не меняет основную конфигурацию. Оно только открывает расширению доступ к описанию объекта.

Обращение к реквизитам документов и справочников

Модуль объекта

В расширении модуль заимствованного объекта содержит только процедуры, которые вы перехватываете. Обращение к реквизитам идёт как в обычном коде, через ЭтотОбъект:

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

Здесь Контрагент взят из основной конфигурации, а мр_ПроверятьКонтрагента добавлен самим расширением. В коде они выглядят одинаково.

Какую директиву выбрать:

  • &Перед — выполнить свой код до штатной процедуры;
  • &После — после неё;
  • &Вместо — заменить штатный код, при этом вызвать оригинал можно через ПродолжитьВызов();
  • &ИзменениеИКонтроль — править кусок штатного кода с контролем изменений при обновлении.

Директива &Вместо ломает цепочку обновлений: если поставщик изменит процедуру, ваша замена продолжит работать по старой логике. Начинайте с &После и &Перед.

Ссылка на объект

Если у вас на руках только ссылка, прочитайте реквизит через неё. Для одного значения это самый короткий путь:

ДатаДоговора = ОбщегоНазначения.ЗначениеРеквизитаОбъекта(Договор, "Дата");

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

Реквизиты табличных частей

Табличная часть читается так же: Для Каждого Строка Из ЭтотОбъект.Товары Цикл. Реквизит расширения в строке получает значение как обычное поле строки. Если табличную часть добавило расширение, её нужно искать в собственных объектах расширения.

Предопределённые элементы и константы

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

ВидЦены = Справочники.ВидыЦен.Оптовая;

Если ту же «Оптовую» добавили в расширении, обращение выглядит так же, но работает, только пока расширение подключено. Без него в базе остаётся ссылка, которая не разворачивается в имя.

Константа читается и пишется через менеджер:

ТекущееЗначение = Константы.мр_ЛимитОтгрузки.Получить();
Константы.мр_ЛимитОтгрузки.Установить(5000);

Что здесь стоит знать:

  • 🔹 Константы основной конфигурации после заимствования читаются из расширения тем же кодом.
  • 🔹 Константа, созданная расширением, при отключении расширения теряет доступ: данные в таблицах остаются, но платформа их не показывает.
  • 🔹 Права на чтение и запись константы выдаются ролями. Роль расширения нужно назначить пользователю отдельно.

Регистры сведений и накопления

Для регистра сведений основной конфигурации заимствуйте регистр и работайте через менеджер записи:

Запись = РегистрыСведений.мр_ЛимитыКонтрагентов.СоздатьМенеджерЗаписи();
Запись.Контрагент = Контрагент;
Запись.Прочитать();
Если Запись.Выбран() Тогда
    Лимит = Запись.Лимит;
КонецЕсли;

Для накопления проще всего построить запрос к виртуальной таблице остатков. Перебирать записи в цикле не нужно, это дорого по времени.

Практические ориентиры:

ЗадачаИнструмент
Одно значение по ключуМенеджер записи регистра сведений
Остатки, оборотыВиртуальные таблицы в запросе
Массовая записьНабор записей регистра (СоздатьНаборЗаписей)

Поля, которые добавило расширение, доступны в запросе под своим именем. Если регистр заимствован, но нужное поле создано в расширении, при открытии конфигурации основной конфигурации оно не отобразится.

Реквизит в форме и динамическом списке

Реквизит на форму выводится двумя способами: перетаскиванием в дереве формы и программным созданием элементов.

Для заимствованной формы:

  1. Откройте форму объекта в расширении (она заимствуется отдельно).
  2. Перетащите реквизит объекта на форму. Для собственного реквизита расширения он доступен в списке «Объект».
  3. Перенесите расположение и задайте заголовок.
  4. Обработчики событий добавляйте через перехват процедур формы.

Если нужно создать элемент из кода, используйте Элементы.Добавить, а реквизит формы добавьте через ИзменитьРеквизиты:

&НаСервере
&После("ПриСозданииНаСервере")
Процедура мр_ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    Реквизиты = Новый Массив;
    Реквизиты.Добавить(Новый РеквизитФормы("мр_Примечание", Новый ОписаниеТипов("Строка")));
    ИзменитьРеквизиты(Реквизиты);
КонецПроцедуры

Динамический список

В форме списка поля берутся из основной таблицы. Чтобы добавить собственное поле:

  • включите «Произвольный запрос» у динамического списка и добавьте поле в текст запроса;
  • либо откройте настройку списка и подключите реквизит расширения как поле основной таблицы, если тип списка это допускает.

Если после обновления поле пропало, посмотрите, не изменил ли поставщик текст запроса списка. В таком случае повторите правку на новом запросе.

Запросы, типы и запись реквизитов расширения

Запрос к реквизиту

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

Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
|    Номенклатура.Ссылка КАК Ссылка,
|    Номенклатура.мр_СрокГодности КАК СрокГодности
|ИЗ
|    Справочник.Номенклатура КАК Номенклатура
|ГДЕ
|    Номенклатура.мр_СрокГодности > 0";
Выборка = Запрос.Выполнить().Выбрать();

Что стоит учесть:

  • 🔹 Запрос с реквизитом расширения работает, только пока расширение подключено. Если расширение отключат, запрос выдаст ошибку компиляции.
  • 🔹 Через точку по ссылке (Номенклатура.Ссылка.мр_СрокГодности) можно ходить на несколько уровней, но каждое соединение замедляет выборку. Для больших таблиц лучше вывести значение отдельным полем.
  • 🔹 Реквизит расширения можно использовать в условиях, группировках и сортировках так же, как и штатный.

Отбор и сортировка по реквизиту в списке

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

Типы реквизитов: на что обратить внимание

Тип реквизита влияет на то, как с ним безопасно работать. Особенно это важно для ссылок на объекты расширения.

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

Не храните в реквизите расширения ссылки на объекты, которые создаёт то же расширение, если планируете когда-нибудь его отключать. Такие значения превратятся в пустые ссылки.

Для хранилища значения пример выглядит так:

Значение = ЭтотОбъект.мр_Данные.Получить();
ЭтотОбъект.мр_Данные = Новый ХранилищеЗначения(НовоеЗначение, Новый СжатиеДанных(9));

Запись реквизита и контроль изменений

Читать значение проще, чем записывать. При записи в реквизит из расширения нужно помнить про три вещи.

  1. Запись идёт через объект: получили объект (Ссылка.ПолучитьОбъект()), изменили, вызвали Записать(). Блокировка объекта на время изменения снижает риск конфликтов.
  2. Если реквизит заимствованный и «только для чтения» в штатной логике, изменение лучше делать в обработчике &После("ПередЗаписью"), а не перед открытием формы.
  3. Для массовых изменений используйте обработки по списку объектов, а не цикл в обработчике формы: так проще откатить результат.

Пример безопасной записи:

Объект = Справочники.Номенклатура.НайтиПоКоду("00-000123").ПолучитьОбъект();
Объект.мр_СрокГодности = 365;
Объект.Записать();

Перед массовым изменением реквизитов выгрузите затронутые данные в файл или сделайте копию базы. Откатить пакетную запись без резервной копии трудно.

Ещё одна деталь касается обновлений. При переходе на новый релиз типовой конфигурации платформа сверяет заимствованные объекты с основной конфигурацией. Если поставщик удалил или переименовал реквизит, в расширении появляется расхождение, и его нужно разобрать вручную: открыть заимствованный объект, посмотреть сообщения о несоответствии и поправить обращения в коде. Чем меньше заимствованных объектов и перехваченных процедур, тем короче эта работа. Поэтому держите расширение небольшим и выносите бизнес-логику в собственные общие модули: они от обновлений не зависят, а в перехватах остаются только короткие вызовы.

Типичные ошибки и отладка

Сообщения платформы меняются от версии к версии, поэтому ищите причину по симптому.

СимптомПричинаЧто делать
Поле объекта не найденоРеквизит не заимствован или расширение не примененоЗаимствуйте объект, примените расширение
В основной конфигурации код не компилируетсяСсылка на реквизит, существующий только в расширенииУберите ссылку, вынесите логику в расширение
Реквизит на форме пустойРеквизит не привязан к данным формыПроверьте путь к данным реквизита
После обновления код не работаетПоставщик изменил процедуру или формуСверьте заимствованные объекты с новой версией

Что проверить по порядку:

  1. Расширение подключено и «Изменяет и дополняет конфигурацию» включён.
  2. Объект заимствован, а не просто упомянут в коде.
  3. Код выполняется в нужном контексте: реквизит читается на сервере, а на клиенте он доступен только через данные формы.

Отладка идёт как обычно. Расширение можно отлаживать при запуске конфигуратора в режиме отладки, а затем остановиться на нужной строке. Если расширения не видны отладчику, проверьте, что они применены в той базе, которую вы отлаживаете.

Прежде чем править рабочую базу, сделайте резервную копию и обкатайте расширение на копии.

Проверка перед выкладкой расширения
Выполнено: 0 / 5

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

Можно ли из основной конфигурации обратиться к реквизиту расширения?
Напрямую нет: основная конфигурация не знает о таких реквизитах. Логику, которая работает с ними, выносят в расширение.
Нужно ли заимствовать объект, чтобы только читать его реквизит?
Для работы с типовыми реквизитами в модулях и формах расширения заимствование нужно. Чтение отдельного значения по ссылке через запрос возможно и без него.
Что будет с данными реквизита, если расширение отключить?
Данные остаются в базе, но платформа их не показывает. После повторного подключения расширения значения снова доступны.
Чем отличается &Вместо от &После?
&Вместо заменяет штатную процедуру, &После только дополняет её. Первый вариант рискованнее при обновлении типовой конфигурации.
Можно ли добавить реквизит в справочник расширением?
Да, у заимствованного объекта можно создать собственный реквизит. Он существует только пока расширение подключено.