Как исправить ошибку «Поле родитель не доступно для записи» при загрузке многоуровневой номенклатуры в 1С?

Программист 1С v8.3 (Обычные формы) IT и автоматизация бизнеса
← На главную

При программной загрузке иерархических справочников (например, справочника Номенклатура) разработчики часто сталкиваются с ошибкой, указывающей на то, что поле Родитель недоступно для записи. Проанализируем причину возникновения этой проблемы и рассмотрим правильные варианты реализации программной загрузки элементов с несколькими уровнями вложенности.

Причина возникновения ошибки

Выясним причину, почему возникает ошибка вида Поле "Родитель" не доступно для записи. В платформе 1С:Предприятие существует четкое разграничение между ссылкой на элемент (СправочникСсылка) и непосредственно объектом данных (СправочникОбъект).

Объект типа СправочникСсылка предназначен исключительно для чтения данных из базы. Любые попытки изменить его свойства или свойства вышестоящих элементов через обращение по цепочке вида Элм.Родитель.Родитель = НовоеЗначение приведут к ошибке, так как Элм.Родитель возвращает ссылку, а не редактируемый объект.

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

Разбор некорректного кода

Рассмотрим пример кода, в котором была допущена ошибка:


// Попытка напрямую изменить родителя у родителя (через ссылку)
Если ИтогГрупп2.Количество() > 0 Тогда
    Элм.Родитель.Родитель = ИтогГрупп2[0].Ссылка; // Ошибка: Элм.Родитель является ссылкой!
Иначе
    ГруппаСПР2 = Справочники.Номенклатура.СоздатьГруппу();
    ГруппаСПР2.Наименование = Группа2;
    ГруппаСПР2.Записать();
    Элм.Родитель.Родитель = ГруппаСПР2.Ссылка; // Ошибка!
КонецЕсли;

В приведенном фрагменте присвоение выполняется для свойства Родитель объекта Элм.Родитель. Так как Элм.Родитель — это СправочникСсылка, платформа блокирует запись.

Правильное решение проблемы

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

  1. Получим объект родительской группы с помощью метода ПолучитьОбъект().
  2. Присвоим реквизиту Родитель этого объекта ссылку на вышестоящую группу.
  3. Запишем измененную родительскую группу вызовом метода Записать().

Рассмотрим исправленный вариант работы с объектом родителя:


// Получаем объект родительской группы из имеющейся ссылки
ОбъектРодителя = Элм.Родитель.ПолучитьОбъект();

Если ОбъектРодителя <> Неопределено Тогда
    // Устанавливаем вышестоящего родителя для найденной группы
    ОбъектРодителя.Родитель = СсылкаНаВышестоящуюГруппу;
    ОбъектРодителя.Записать();
КонецЕсли;

Рекомендации по правильной загрузке многоуровневой иерархии

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

1. Поиск группы с учетом родителя

Если в справочнике могут существовать папки с одинаковыми названиями в разных ветках, поиск по одному лишь наименованию вернет неверную группу. В запросе или при использовании метода НайтиПоНаименованию() всегда следует указывать родительскую группу предыдущего уровня:


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

Запрос.УстановитьПараметр("Наименование", ИмяТекущейГруппы);
Запрос.УстановитьПараметр("Родитель", РодительВерхнегоУровня);

Результат = Запрос.Выполнить();

2. Последовательное создание структуры сверху вниз

Наиболее надежный способ — последовательное создание или поиск групп по цепочке, начиная от самого верхнего корневого уровня к нижнему:

  1. Проверяем существование корневой группы (родитель = СправочникСсылка.Номенклатура.ПустаяСсылка()). При отсутствии — создаем ее и сохраняем ссылку.
  2. Ищем или создаем группу второго уровня, указывая в качестве родителя ссылку на созданную корневую группу.
  3. Назначаем итоговую группу в качестве значения реквизита Родитель для самого элемента номенклатуры.

Такой подход полностью исключает необходимость редактирования уже привязанных родителей «снизу вверх» и защищает код от ошибок доступа на запись.

← На главную