В современных конфигурациях 1С, построенных на базе Библиотеки стандартных подсистем (БСП), таких как 1С:Управление торговлей 11.4, 1С:ERP или 1С:Комплексная автоматизация, механизм дополнительных реквизитов и сведений является стандартом для расширения свойств объектов без изменения метаданных конфигурации. Однако при программной работе с ними начинающие разработчики часто сталкиваются со специфическими ошибками: от неотображения реквизитов в пользовательском интерфейсе до серьезных сбоев блокировок СУБД ("несоответствие версии базы данных").
В этой статье мы подробно разберем, как устроена архитектура дополнительных реквизитов в 1С, как правильно заполнять их программно различными способами, и детально проанализируем причины возникновения популярных ошибок при разработке.
Прежде чем приступать к написанию кода, давайте разберемся в структуре хранения данных. В 1С:УТ 11 дополнительные реквизиты и дополнительные сведения — это два принципиально разных механизма:
ДополнительныеСведения. Их изменение не влияет на версию самого объекта (например, номенклатуры) и не требует его перезаписи.ДополнительныеРеквизиты. Каждый элемент этой табличной части содержит две ключевые колонки: Свойство (ссылка на План видов характеристик ДополнительныеРеквизитыИСведения) и Значение (тип значения зависит от настройки свойства).Поскольку дополнительные реквизиты являются частью самого объекта номенклатуры, любое их изменение напрямую перезаписывает объект и меняет его версию в базе данных.
Для управления дополнительными свойствами в БСП предусмотрен специальный общий модуль — УправлениеСвойствами. Этот способ является наиболее безопасным и рекомендуемым разработчиками фирмы 1С, так как он автоматически выполняет все необходимые проверки прав доступа, типов данных и корректности заполнения.
Для записи свойств нам потребуется подготовить таблицу значений определенной структуры и передать ее в метод общего модуля. Давайте рассмотрим пошаговый пример реализации этого подхода:
// 1. Создаем таблицу для передачи свойств и значений
ТаблицаСвойствИЗначений = Новый ТаблицаЗначений;
ТаблицаСвойствИЗначений.Колонки.Добавить("Свойство");
ТаблицаСвойствИЗначений.Колонки.Добавить("Значение");
// 2. Находим нужное нам свойство (дополнительный реквизит)
// Обратите внимание: поиск по наименованию может быть нестабилен, ниже мы разберем более надежный способ
СвойствоАвтор = ПланыВидовХарактеристик.ДополнительныеРеквизитыИСведения.НайтиПоНаименованию("Автор");
Если ЗначениеЗаполнено(СвойствоАвтор) Тогда
// 3. Добавляем строку с новым значением
НоваяСтрока = ТаблицаСвойствИЗначений.Добавить();
НоваяСтрока.Свойство = СвойствоАвтор;
НоваяСтрока.Значение = "Александр Пушкин"; // Указываем необходимое значение
КонецЕсли;
// 4. Если таблица не пустая, записываем свойства объекта через БСП
Если ТаблицаСвойствИЗначений.Количество() > 0 Тогда
// ВладелецСвойств - это ССЫЛКА на элемент номенклатуры (например, СсылкаНоменклатуры)
УправлениеСвойствами.ЗаписатьСвойстваУОбъекта(СсылкаНоменклатуры, ТаблицаСвойствИЗначений);
КонецЕсли;
Важное преимущество метода БСП: процедура УправлениеСвойствами.ЗаписатьСвойстваУОбъекта самостоятельно получает объект по ссылке, заполняет его табличную часть и производит безопасную запись в базу данных. Вам не нужно вручную вызывать метод Записать() у объекта номенклатуры.
Часто разработчики допускают критическую ошибку, пытаясь совместить создание новой номенклатуры и вызов методов БСП в одном цикле. Сценарий выглядит следующим образом:
НоваяНоменклатура = Справочники.Номенклатура.СоздатьЭлемент();НоваяНоменклатура.Записать(); (объект получает версию 1).УправлениеСвойствами.ЗаписатьСвойстваУОбъекта(НоваяНоменклатура.Ссылка, ТаблицаСвойств);. Внутри этого метода БСП считывает объект из базы, заполняет его табличную часть и записывает. Версия объекта в базе данных становится равной 2.НоваяНоменклатура, которая в памяти все еще хранит версию 1. Происходит вызов НоваяНоменклатура.Записать();. Платформа 1С сверяет версии, видит конфликт изменений и выбрасывает исключение: "Операция не может быть выполнена из-за несоответствия версии...".Как этого избежать? Если вы используете общий модуль УправлениеСвойствами, никогда не записывайте объект повторно после вызова процедуры записи свойств! БСП берет всю работу по обновлению СУБД на себя.
Если вы создаете новый элемент номенклатуры или уже открыли объект для редактирования в коде, самым производительным и правильным решением будет прямое заполнение его табличной части ДополнительныеРеквизиты в памяти. Этот способ работает в разы быстрее, так как сохранение объекта в базу данных происходит ровно один раз.
Давайте разберем по шагам, как это реализовать:
// Создаем новый объект номенклатуры в памяти
НовыйТовар = Справочники.Номенклатура.СоздатьЭлемент();
НовыйТовар.Наименование = "Книга 'Капитанская дочка'";
НовыйТовар.ВидНоменклатуры = СсылкаНаВидНоменклатуры; // Обязательно для заполнения!
// Ищем доп. реквизит
СвойствоАвтор = ПланыВидовХарактеристик.ДополнительныеРеквизитыИСведения.НайтиПоНаименованию("Автор");
Если ЗначениеЗаполнено(СвойствоАвтор) Тогда
// Напрямую добавляем строку в табличную часть объекта
НоваяСтрока = НовыйТовар.ДополнительныеРеквизиты.Добавить();
НоваяСтрока.Свойство = СвойствоАвтор;
НоваяСтрока.Значение = "А.С. Пушкин";
КонецЕсли;
// Производим ЕДИНСТВЕННУЮ запись объекта в базу данных
НовыйТовар.Записать();
Этот способ полностью исключает ошибки оптимистической блокировки версий и экономит ресурсы сервера 1С и СУБД, сводя количество транзакций записи к минимуму.
Использование метода НайтиПоНаименованию() для планов видов характеристик — это плохой тон в программировании 1С. Пользователь в режиме "1С:Предприятие" может в любой момент переименовать реквизит "Автор" в "Автор книги", "Создатель" или "Писатель", после чего ваш программный код полностью перестанет работать.
Для решения этой проблемы БСП при создании дополнительного реквизита автоматически генерирует для него уникальный строковый идентификатор, который записывается в реквизит Имя (например, Автор_7dfb36a1eac98...). Этот идентификатор остается неизменным, как бы пользователь ни переименовывал реквизит на форме.
Рекомендуется выполнять поиск свойства именно по этому идентификатору:
// Безопасный поиск свойства по его системному имени в БСП
ИмяСвойства = "Автор_6fb1a21e0ca843a99bb8f1aee6d1ff82"; // Получаем из карточки доп. реквизита
СвойствоСсылка = ПланыВидовХарактеристик.ДополнительныеРеквизитыИСведения.НайтиПоРеквизиту("Имя", ИмяСвойства);
Если Не ЗначениеЗаполнено(СвойствоСсылка) Тогда
ВызватьИсключение "Критическая ошибка: Дополнительный реквизит '" + ИмяСвойства + "' не найден в базе данных!";
КонецЕсли;
При программном заполнении дополнительных реквизитов вы всегда должны помнить о бизнес-логике конфигурации 1С:Управление торговлей. Дополнительные реквизиты не существуют "сами по себе" — они привязаны к определенным Наборам свойств, которые, в свою очередь, привязаны к Видам номенклатуры.
Если вы программно запишете в табличную часть номенклатуры свойство, которое не входит в набор свойств, соответствующий текущему виду номенклатуры этого товара, произойдет следующее:
Перед программным заполнением всегда проверяйте, добавлено ли ваше свойство в настройки соответствующего вида номенклатуры в режиме "1С:Предприятие".
Для обратной задачи — чтения данных — также не обязательно писать громоздкие запросы к табличным частям. БСП предоставляет удобные готовые функции для быстрого извлечения значений.
Пример чтения конкретного реквизита:
// Получаем значение одного конкретного дополнительного реквизита по ссылке номенклатуры
ЗначениеАвтора = УправлениеСвойствами.ЗначениеСвойства(СсылкаНоменклатуры, СвойствоСсылка);
Пример чтения всех реквизитов объекта сразу:
// Получаем таблицу всех заполненных свойств для номенклатуры
ТаблицаЗначенийСвойств = УправлениеСвойствами.ЗначенияСвойств(СсылкаНоменклатуры);
Для Каждого СтрокаСвойства Из ТаблицаЗначенийСвойств Цикл
Сообщить("Свойство: " + СтрокаСвойства.Свойство + " | Значение: " + СтрокаСвойства.Значение);
КонецЦикла;
Мы детально разобрали особенности работы с дополнительными реквизитами номенклатуры в конфигурациях на базе БСП. Для обеспечения стабильной работы ваших интеграций и обработок загрузки всегда придерживайтесь трех простых правил:
ДополнительныеРеквизиты перед вызовом Записать(). Это сохранит транзакционную целостность и сэкономит время работы СУБД.УправлениеСвойствами.ЗаписатьСвойстваУОбъекта и не вызывайте после него метод записи самого объекта номенклатуры.Имя, чтобы защитить ваш программный код от переименований со стороны пользователей.