В практике разработки на платформе «1С:Предприятие 8.3» часто возникает загадочная ситуация: программно записанный реквизит ведет себя как «призрак». Консоль запросов без проблем извлекает значение из базы данных, при открытии карточки объекта в режиме просмотра значение может отображаться, но стоит пользователю нажать кнопку «Редактировать» или «Записать», как реквизит бесследно исчезает.
В этой статье мы подробно разберем, почему возникает подобный эффект «в базе есть, а на форме нет», проанализируем влияние режима ОбменДанными.Загрузка = Истина, выявим синтаксические ошибки при работе с дополнительными свойствами и рассмотрим правильный, безопасный шаблон программной записи дополнительных реквизитов с использованием Библиотеки стандартных подсистем (БСП).
---
Для начала детально разберем физику процесса. Проблема, как правило, берет свое начало из кода программного заполнения свойств. Давайте посмотрим на некорректный фрагмент кода, который приводит к такому поведению:
ОбъектСсылки = Ссылка.ПолучитьОбъект();
НовоеСвойство = ОбъектСсылки.ДополнительныеРеквизиты.Добавить();
НовоеСвойство.Свойство = ПланыВидовХарактеристик.ДополнительныеРеквизитыИСведения.НайтиПоНаименованию("У поставщика");
НовоеСвойство.Значение = "ТекстовоеЗначение"; // Здесь пишется обычная строка!
ОбъектСсылки.ОбменДанными.Загрузка = Истина;
ОбъектСсылки.ДополнительныеСвойства.Вставить("ОтключитьМеханизмРегистрацииОбъектов");
ОбъектСсылки.Записать();
Проанализируем по шагам, что происходит в СУБД и на уровне платформы при выполнении этого кода:
ОбменДанными.Загрузка = Истина сообщает платформе 1С о том, что объект записывается в режиме обмена (синхронизации). При этом полностью отключаются все стандартные проверки бизнес-логики в модуле объекта (обработчики ПередЗаписью, ПриЗаписи) и в подписках на события. Платформа считает, что данные приходят из доверенного источника, поэтому они записываются в базу данных «как есть».ЗначенияСвойствОбъектов). Программа ожидает получить ссылку на элемент этого справочника. Однако в коде в поле Значение передается обычная текстовая строка. Из-за отключенных проверок СУБД успешно сохраняет эту строку в табличную часть объекта.ДополнительныеРеквизитыИСведения. Обнаружив, что для свойства «У поставщика» назначен ссылочный тип, код БСП пытается преобразовать прочитанное из базы данных значение (строку) в объект типа СправочникСсылка.ЗначенияСвойствОбъектов. Естественно, преобразовать произвольный текст в ссылку невозможно. Происходит тихий сбой приведения типов, и элемент формы визуально остается пустым.Загрузка = Истина не установлен). Код БСП считывает данные из элементов управления формы. Поскольку поле ввода на форме было пустым, БСП перезаписывает табличную часть объекта актуальными (пустыми) значениями с формы. В результате «криво» записанная строка окончательно удаляется из базы данных.---
Обратим внимание на следующую строку из приведенного выше примера:
ОбъектСсылки.ДополнительныеСвойства.Вставить("ОтключитьМеханизмРегистрацииОбъектов");
В данном вызове содержатся сразу две критические ошибки:
Вставить() объекта Структура в 1С требует обязательной передачи двух параметров: ключа и значения: Вставить(<Ключ>, <Значение>). Попытка передать только один параметр во многих версиях платформы приведет к аварийному завершению работы кода с ошибкой «Недостаточно фактических параметров» либо запишет в значение пустой инициализатор Неопределено.ОтключитьМеханизмРегистрацииОбъектов используется для того, чтобы подсистема обмена данными БСП не регистрировала изменения объекта на узлах планов обмена при его программной записи. Для корректной отработки этого флага значение обязательно должно быть передано как Булево Истина.Правильный синтаксис для отключения регистрации изменений выглядит следующим образом:
ОбъектСсылки.ДополнительныеСвойства.Вставить("ОтключитьМеханизмРегистрацииОбъектов", Истина);
---
Прямое добавление строк в табличную часть ДополнительныеРеквизиты объекта — это архитектурный антипаттерн при работе с конфигурациями на базе БСП. Такой подход лишает вас возможности автоматического контроля типов данных и связей.
Для корректной работы мы должны использовать специализированный программный интерфейс БСП — общий модуль УправлениеСвойствами. Рассмотрим подробный алгоритм правильной записи.
Шаг 1. Поиск или создание элемента в справочнике «Значения свойств объектов»
Если тип реквизита ссылается на дополнительные значения, мы не можем записать туда строку. Сначала необходимо найти или создать элемент в справочнике ЗначенияСвойствОбъектов, где владельцем обязательно должно выступать наше свойство из ПВХ.
Шаг 2. Использование метода «ЗаписатьСвойстваУОбъекта»
Этот метод общего модуля УправлениеСвойствами берет на себя всю рутину: он открывает транзакцию, сверяет типы данных по метаданным БСП, осуществляет запись свойств и корректно сохраняет сам объект.
Рассмотрим пример правильной реализации заполнения дополнительного реквизита:
// Определим ссылку на объект номенклатуры, для которого пишем реквизит
СсылкаНаОбъект = Справочники.Номенклатура.НайтиПоРеквизиту("Код", "00000001");
Если Не СсылкаНаОбъект.Пустая() Тогда
// 1. Получаем само свойство (доп. реквизит) из ПВХ
СвойствоУПоставщика = ПланыВидовХарактеристик.ДополнительныеРеквизитыИСведения.НайтиПоНаименованию("У поставщика");
Если ЗначениеЗаполнено(СвойствоУПоставщика) Тогда
// 2. Ищем элемент справочника "Значения свойств объектов" по наименованию и владельцу
ЗначениеСвойстваСсылка = Справочники.ЗначенияСвойствОбъектов.НайтиПоНаименованию("ИскомоеЗначение", Истина, , СвойствоУПоставщика);
// Если значения в базе еще нет, создаем его программно с привязкой к владельцу
Если ЗначениеСвойстваСсылка.Пустая() Тогда
НовоеЗначениеОбъект = Справочники.ЗначенияСвойствОбъектов.СоздатьЭлемент();
НовоеЗначениеОбъект.Владелец = СвойствоУПоставщика;
НовоеЗначениеОбъект.Наименование = "ИскомоеЗначение";
Попытка
НовоеЗначениеОбъект.Записать();
ЗначениеСвойстваСсылка = НовоеЗначениеОбъект.Ссылка;
Исключение
ВызватьИсключение "Не удалось записать новое значение свойства: " + КраткоеПредставлениеОшибки(ИнформацияОбОшибке());
КонецПопытки;
КонецЕсли;
// 3. Подготавливаем структуру для записи через программный интерфейс БСП
ТаблицаСвойств = Новый Массив;
СтрокаСвойства = Новый Структура("Свойство, Значение", СвойствоУПоставщика, ЗначениеСвойстваСсылка);
ТаблицаСвойств.Добавить(СтрокаСвойства);
// 4. Безопасно записываем свойства у объекта
Попытка
УправлениеСвойствами.ЗаписатьСвойстваУОбъекта(СсылкаНаОбъект, ТаблицаСвойств);
Сообщить("Дополнительный реквизит успешно записан!");
Исключение
Сообщить("Ошибка при записи дополнительных свойств: " + КраткоеПредставлениеОшибки(ИнформацияОбОшибке()));
КонецПопытки;
Иначе
Сообщить("Не найдено свойство (доп. реквизит) с наименованием 'У поставщика'!");
КонецЕсли;
КонецЕсли;
---
Для того чтобы избежать ошибок "исчезающих" данных при работе с дополнительными реквизитами БСП, всегда придерживайтесь трех золотых правил разработчика 1С:
ДополнительныеСвойства, всегда указывайте второй аргумент (значение флага), например: Вставить("ОтключитьМеханизмРегистрацииОбъектов", Истина).УправлениеСвойствами. Это гарантирует сохранность данных и корректное поведение интерфейса управляемых форм.