В процессе разработки конфигураций и написания внешних обработок в 1С разработчики нередко сталкиваются с ситуацией: перед вызовом метода Записать() все реквизиты объекта заполнены корректно, однако сразу после выполнения записи или при повторном открытии объекта один из реквизитов (например, Родитель) оказывается пустым. Разберем по шагам, почему платформа или прикладной код сбрасывают значение и как быстро локализовать источник проблемы.
Когда мы вызываем метод Записать() у объектной переменной, инициируется транзакция записи, в рамках которой неявно выполняется цепочка стандартных событий платформы. Если реквизит очищается именно в момент вызова метода, корень проблемы практически всегда кроется в прикладном коде конфигурации.
Проанализируем ключевые места, где может происходить изменение значений:
ПередЗаписью() и ПриЗаписи(). В типовых и кастомизированных решениях в этих процедурах часто вызываются функции автозаполнения, проверки корректности реквизитов или сброса неактуальных связей.ПодпискаНаСобытие, у которых в качестве источника указан тип записываемого справочника, а событием выступает ПередЗаписью или ПриЗаписи. Подписки выполняются до или после обработчиков модуля объекта и могут незаметно изменять состояние переданного источника.Выясним причину, связанную с особенностями структуры метаданных иерархических подчиненных справочников. Если справочник одновременно имеет владельца и поддерживает иерархию, платформа 1С строго контролирует логическую целостность дерева данных.
Если реквизит Владелец устанавливается после реквизита Родитель, либо если у выбранного родительского элемента владелец отличается от владельца текущего элемента, платформа автоматически сбрасывает значение реквизита Родитель, предотвращая нарушение ссылочной целостности.
Рассмотрим правильный порядок программного заполнения таких объектов:
НовыйЭлемент = Справочники.УпаковкиНоменклатуры.СоздатьЭлемент();
// Сначала обязательно устанавливаем владельца
НовыйЭлемент.Владелец = ТекущаяНоменклатура;
// Проверяем, что у родительской папки тот же владелец
Если ГруппаУпаковок.Владелец = ТекущаяНоменклатура Тогда
НовыйЭлемент.Родитель = ГруппаУпаковок;
КонецЕсли;
НовыйЭлемент.Наименование = "Коробка 10 шт";
НовыйЭлемент.Записать();
Рассмотрим еще одну распространенную причину сброса родительского узла. В метаданных справочника может быть настроен вид иерархии Иерархия групп и элементов. В такой структуре родителем может выступать только группа.
Если в поле Родитель программно передается ссылка на обычный элемент, у которого реквизит ЭтоГруппа равен Ложь, встроенные механизмы валидации платформы или модуля объекта очистят недопустимое значение или вызовут ошибку записи. Перед присвоением убедимся, что родитель действительно является группой:
Если РодительскаяСсылка.ЭтоГруппа Тогда
ОбъектСправочника.Родитель = РодительскаяСсылка;
Иначе
ВызватьИсключение "Выбранный родительский элемент не является группой!";
КонецЕсли;
Разберем по шагам, как локализовать место, где конкретно обнуляется реквизит, если визуальный осмотр кода не дает результатов:
ПодпискаНаСобытие. Перейдем в назначенные им обработчики в общих модулях.Записать() и остановим замер. В сформированной таблице мы увидим абсолютно все строки процедур и функций, которые выполнились во время транзакции записи.ПередЗаписью() модуля записываемого объекта и пошагово с помощью клавиши F11 пройдем все внутренние вызовы служебных модулей конфигурации.В задачах переноса данных или синхронизации часто требуется записать элемент в базу данных строго в том виде, в котором он сформирован, без выполнения переопределяющей прикладной логики конфигурации. Для этого перед вызовом записи активируем режим загрузки данных:
ОбъектСправочника.ОбменДанными.Загрузка = Истина;
ОбъектСправочника.Записать();
Важно: свойство ОбменДанными.Загрузка = Истина отключает выполнение большинства проверок в процедурах ПередЗаписью и ПриЗаписи типовых конфигураций, позволяя сохранить объект без вмешательства логики типового функционала.