Разработка и Конфигурация · 12 мин
Как записать дополнительный реквизит в 1С 8.3 программно
Как записать дополнительный реквизит в 1С 8.3 программно: работа с табличной частью ДополнительныеРеквизиты, поиск свойства, примеры кода, типичные ошибки.
Дополнительные реквизиты в 1С 8.3 — это механизм БСП (Библиотеки стандартных подсистем), который позволяет расширять объекты без изменения конфигурации. Значения хранятся в табличной части «ДополнительныеРеквизиты» самого объекта, а описания свойств — в плане видов характеристик «ДополнительныеРеквизитыИСведения». Поэтому программная запись сводится к трём шагам: найти свойство, найти или добавить строку в табличной части, записать значение и сохранить объект.
Главная сложность — правильно идентифицировать свойство. Пользователь видит заголовок («Цвет», «Вес брутто»), но в базе свойство — это ссылка на элемент плана видов характеристик, у которого есть имя для поиска, заголовок и уникальный идентификатор. Искать по заголовку ненадёжно: пользователь может его переименовать. Надёжнее искать по имени или хранить ссылку на свойство в параметрах обработки.
Ниже разобран полный рабочий цикл: от поиска свойства до записи объекта, включая вариант с дополнительными сведениями, типовые ошибки и способы проверки результата. Примеры кода применимы к любой типовой конфигурации на БСП — УТ, ERP, БП, ЗУП.
Где физически хранятся значения дополнительных реквизитов
Прежде чем писать код, важно понимать структуру хранения — от неё зависит, какой объект модифицировать. В БСП существует два похожих механизма, и их часто путают.
Дополнительные реквизиты хранятся в табличной части «ДополнительныеРеквизиты» самого объекта (справочника «Номенклатура», документа «РеализацияТоваровУслуг» и т.д.). Табличная часть содержит колонки «Свойство» (ссылка на ПВХ) и «Значение» (характеристика произвольного типа). Записываются вместе с объектом одним вызовом Записать().
Дополнительные сведения хранятся отдельно — в регистре сведений «ДополнительныеСведения» с измерениями «Объект» и «Свойство». Они не требуют перезаписи самого объекта, что удобно, когда объект заблокирован или его нельзя изменять (например, проведённый документ в закрытом периоде).
Шаг 1. Как найти нужное свойство программно
Свойство — это элемент плана видов характеристик «ДополнительныеРеквизитыИСведения». Есть три способа получить на него ссылку, и они различаются по надёжности.
Самый надёжный способ — поиск по имени свойства через метод БСП. Имя формируется автоматически при создании свойства и не меняется при переименовании заголовка:
Свойство = УправлениеСвойствами.СвойствоПоИмени("Цвет_Номенклатуры");
Второй способ — запрос по заголовку. Он проще, но ломается, если пользователь переименует реквизит в настройках:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ ПЕРВЫЕ 1
| ДопРеквизиты.Ссылка КАК Свойство
|ИЗ
| ПланВидовХарактеристик.ДополнительныеРеквизитыИСведения КАК ДопРеквизиты
|ГДЕ
| ДопРеквизиты.Заголовок = &Заголовок
| И НЕ ДопРеквизиты.ПометкаУдаления";
Запрос.УстановитьПараметр("Заголовок", "Цвет");
Результат = Запрос.Выполнить();
Если Результат.Пустой() Тогда
ВызватьИсключение "Свойство ""Цвет"" не найдено";
КонецЕсли;
Свойство = Результат.Выгрузить()[0].Свойство;
Третий вариант — получить ссылку по уникальному идентификатору, если он известен (например, выгружен из эталонной базы). Это удобно при переносе настроек между базами, где свойства создавались обменом.
Шаг 2. Запись значения в табличную часть объекта
Когда ссылка на свойство получена, логика записи одинакова для любого объекта: получить объект по ссылке, найти строку с этим свойством, обновить её или добавить новую, записать объект.
ОбъектНоменклатуры = СсылкаНоменклатура.ПолучитьОбъект();
ПараметрыОтбора = Новый Структура("Свойство", Свойство);
НайденныеСтроки = ОбъектНоменклатуры.ДополнительныеРеквизиты.НайтиСтроки(ПараметрыОтбора);
Если НайденныеСтроки.Количество() > 0 Тогда
СтрокаРеквизита = НайденныеСтроки[0];
Иначе
СтрокаРеквизита = ОбъектНоменклатуры.ДополнительныеРеквизиты.Добавить();
СтрокаРеквизита.Свойство = Свойство;
КонецЕсли;
СтрокаРеквизита.Значение = "Красный";
ОбъектНоменклатуры.Записать();
Обратите внимание на тип значения. Колонка «Значение» имеет составной тип, но конкретное свойство ограничено типом, заданным в его настройках (строка, число, дата, булево, ссылка на справочник или на «ЗначенияСвойствОбъектов»). Если передать значение несовместимого типа, при записи возникнет ошибка либо значение будет приведено к пустому.
Если значение выбирается из списка (дополнительное значение), записывать нужно ссылку на элемент справочника «ЗначенияСвойствОбъектов», а не строку. Найти его можно запросом по владельцу (свойству) и наименованию.
- 1Получите ссылку на свойство из ПВХ ДополнительныеРеквизитыИСведения
- 2Получите объект методом ПолучитьОбъект()
- 3Найдите строку в табличной части ДополнительныеРеквизиты по отбору Свойство
- 4Обновите существующую строку или добавьте новую и заполните Свойство
- 5Присвойте Значение с учётом типа свойства
- 6Вызовите Записать() и проверьте результат в карточке объекта
Шаг 3. Запись дополнительного сведения через регистр
Если поле заведено как дополнительное сведение (а не реквизит), табличной части у объекта нет — значение пишется в регистр сведений «ДополнительныеСведения». Это делается через менеджер записи:
МенеджерЗаписи = РегистрыСведений.ДополнительныеСведения.СоздатьМенеджерЗаписи();
МенеджерЗаписи.Объект = СсылкаНоменклатура;
МенеджерЗаписи.Свойство = Свойство;
МенеджерЗаписи.Значение = "Проверено ОТК";
МенеджерЗаписи.Записать(Истина);
Параметр Истина в методе Записать() означает замещение существующей записи с теми же измерениями. Если передать Ложь и запись уже существует, возникнет ошибка уникальности.
Преимущество подхода — объект-владелец не перезаписывается, поэтому не срабатывают его подписки на события, не меняется дата изменения и не возникает конфликтов блокировок. Это безопасный способ дозаписать данные к проведённым документам закрытого периода.
Запись в транзакции и при групповой обработке
При массовом заполнении реквизитов (например, обработкой по списку номенклатуры) каждый объект записывается отдельно. Чтобы сбой на середине не оставил данные в рассогласованном состоянии, оборачивайте цикл в транзакцию или, как минимум, обрабатывайте исключения по каждому элементу с накоплением ошибок.
НачатьТранзакцию();
Попытка
Для Каждого Элемент Из СписокОбъектов Цикл
Объект = Элемент.ПолучитьОбъект();
// ... заполнение табличной части ДополнительныеРеквизиты ...
Объект.Записать();
КонецЦикла;
ЗафиксироватьТранзакцию();
Исключение
ОтменитьТранзакцию();
ВызватьИсключение ОписаниеОшибки();
КонецПопытки;
Учитывайте, что длинная транзакция удерживает блокировки и может мешать работе пользователей. Для больших объёмов разумнее писать порциями с фиксацией каждой порции и журналированием необработанных элементов.
Типичные ошибки и как их избежать
Первая частая ошибка — поиск свойства по заголовку без проверки набора. В базе может существовать несколько свойств с одинаковым названием для разных объектов, и запрос вернёт первое попавшееся. Всегда сужайте выборку или используйте поиск по имени.
Вторая ошибка — запись значения несовместимого типа. Если свойство объявлено как «Дополнительное значение», строка «Красный» не запишется корректно: нужна ссылка на элемент справочника значений. Проверяйте реквизит «ТипЗначения» свойства перед записью.
Третья ошибка — вызов Записать() у объекта, полученного как ссылка, без ПолучитьОбъект(). Изменения табличной части через ссылку недоступны: у объекта типа «СправочникСсылка» нет редактируемой табличной части.
Четвёртая — игнорирование прав. У пользователя, под которым выполняется код, может не быть права изменения объекта или интерактивной записи. В серверных процедурах общих модулей с признаком «Привилегированный» эта проблема снимается, но осознанно: привилегированный режим обходит все ограничения доступа.
Как проверить, что значение записалось
Минимальная проверка — открыть карточку объекта в режиме предприятия и убедиться, что реквизит отображается на вкладке «Дополнительно» с нужным значением. Если поле пустое, но код отработал без ошибок, чаще всего записано значение не того типа или не тому свойству.
Программно результат проверяется чтением табличной части свежего объекта или запросом:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ДопРеквизиты.Значение КАК Значение
|ИЗ
| Справочник.Номенклатура.ДополнительныеРеквизиты КАК ДопРеквизиты
|ГДЕ
| ДопРеквизиты.Ссылка = &Ссылка
| И ДопРеквизиты.Свойство = &Свойство";
Запрос.УстановитьПараметр("Ссылка", СсылкаНоменклатура);
Запрос.УстановитьПараметр("Свойство", Свойство);
Выборка = Запрос.Выполнить().Выбрать();
Если Выборка.Следующий() Тогда
Сообщить("Записано значение: " + Выборка.Значение);
Иначе
Сообщить("Значение не найдено — проверьте свойство и тип");
КонецЕсли;
Как проверить результат
Значение отображается на вкладке «Дополнительно»
Поле пустое или содержит не то значение
Запрос возвращает одну строку с нужным значением
Пустой результат или несколько строк с одним свойством
Тип совпадает с типом свойства (строка, ссылка, дата)
Значение приведено к пустому значению типа
Когда какой подход выбирать
Сравнение вариантов
Подходит для дополнительных реквизитов; значения видны в форме объекта и доступны в запросах через точку. Требует перезаписи объекта.
Подходит для дополнительных сведений и для записи без изменения объекта — например, к документам закрытого периода. В отчётах подключается сложнее.
Подходит, когда поле используется в логике и отчётах постоянно. Требует доработки конфигурации и обновления, но даёт полную типизацию и индексацию.
Если поле носит информационный характер и заполняется вручную или изредка обработкой — достаточно дополнительного реквизита. Если по полю строятся отчёты, отборы и проводки, рассмотрите полноценный реквизит конфигурации: запросы по табличной части дополнительных реквизитов медленнее и сложнее в поддержке.
Что важно запомнить
Дополнительный реквизит пишется в табличную часть «ДополнительныеРеквизиты» объекта: свойство ищется в ПВХ «ДополнительныеРеквизитыИСведения», строка обновляется или добавляется, объект записывается. Дополнительные сведения пишутся в регистр «ДополнительныеСведения» без перезаписи объекта. Всегда проверяйте тип значения и принадлежность свойства нужному набору.
Частые вопросы
Чем дополнительный реквизит отличается от дополнительного сведения?
Реквизит хранится в табличной части самого объекта и записывается вместе с ним, сведение — в отдельном регистре сведений и не требует перезаписи объекта. Реквизиты удобнее в запросах и отчётах, сведения безопаснее для документов закрытых периодов.
Как записать значение, если свойство — список значений?
Нужно записать ссылку на элемент справочника «ЗначенияСвойствОбъектов», а не строку. Найдите элемент запросом по владельцу (ваше свойство) и наименованию; если значения нет, создайте его программно, указав владельца.
Почему после Записать() значение в карточке не появилось?
Чаще всего записано значение несовместимого типа (оно очищается) или использовано свойство из чужого набора. Также проверьте, что записывался именно тот объект — получите его заново и прочитайте табличную часть.
Можно ли записать дополнительный реквизит, не открывая форму объекта?
Да, весь описанный код работает на сервере без какой-либо формы: ПолучитьОбъект(), изменение табличной части и Записать() выполняются полностью программно, в том числе в фоновых заданиях и регламентных операциях.
Что делать, если при записи возникает ошибка блокировки?
Объект редактируется другим пользователем или сеансом. Обработайте исключение, повторите попытку с паузой или перенесите запись в фоновое задание. Для массовых обработок ведите список незаписанных объектов и повторяйте их отдельно.
Как удалить значение дополнительного реквизита программно?
Найдите строку в табличной части по отбору «Свойство» и вызовите метод Удалить() табличной части, затем запишите объект. Для сведения — создайте менеджер записи с теми же измерениями и вызовите Удалить().