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

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

При работе с регистрами сведений разработчики часто сталкиваются с ошибкой «Поле объекта не доступно для записи». Проанализируем причину возникновения этой проблемы, разберем типичные ошибки при присвоении значений реквизитам и рассмотрим правильные способы обновления данных в регистрах сведений 1С.

Выясним причину возникновения ошибки

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


Запись.УсловияТруда.Наименование = Справочники.УсловияТруда.НайтиПоКоду(000000001);

В данном фрагменте совмещены сразу две принципиальные ошибки:

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

Если ресурс или измерение регистра сведений УсловияТруда имеет тип СправочникСсылка.УсловияТруда, то присваивать ему нужно саму ссылку на элемент справочника, а не его наименование.

Разберем по шагам правильное решение

Для исправления ошибки и оптимизации работы алгоритма выполним следующие действия:

  1. Вынесем поиск элементов за пределы цикла: Вызов метода НайтиПоКоду() внутри цикла приводит к повторным обращениям к базе данных на каждой итерации. Определение нужных ссылок следует выполнять заранее.
  2. Передадим код в виде строки: Если код справочника является строковым и содержит ведущие нули, передавать его нужно в кавычках (например, "000000001"). В противном случае платформа воспримет значение как число 1 и не сможет найти нужный элемент.
  3. Присвоим ссылку непосредственно ресурсу регистра: Уберем обращение к полю Наименование и присвоим найденную ссылку прямо в измерение или ресурс Запись.УсловияТруда.

Посмотрим на пример правильной реализации:


Процедура КнопкаВыполнитьНажатие(Кнопка)
    
    // Предварительно находим нужные ссылки до входа в цикл
    Условие1 = Справочники.УсловияТруда.НайтиПоКоду("000000001");
    Условие2 = Справочники.УсловияТруда.НайтиПоКоду("000000002");
    
    Регистр = РегистрыСведений.СвойстваПозицииШтатногоРасписания.СоздатьНаборЗаписей();
    
    // При необходимости устанавливаем отбор, чтобы не читать весь регистр
    // Регистр.Отбор.Позиция.Установить(ЗначениеПозиции);
    
    Регистр.Прочитать();
    
    Для Каждого Запись Из Регистр Цикл
        Если Запись.Период <= Дата("20171116") Тогда
            Запись.УсловияТруда = Условие1;
        Иначе
            Запись.УсловияТруда = Условие2;
        КонецЕсли;
    КонецЦикла;
    
    Регистр.Записать(Ложь);
    
КонецПроцедуры

Альтернативный способ: использование Менеджера записи

Если требуется изменить не весь набор, а одну конкретную запись регистра сведений с известным ключом (периодом и измерениями), целесообразнее использовать СоздатьМенеджерЗаписи() вместо набора записей. Это снижает нагрузку на базу данных и упрощает код.

Рассмотрим пример использования менеджера записи:


МенеджерЗаписи = РегистрыСведений.СвойстваПозицииШтатногоРасписания.СоздатьМенеджерЗаписи();

// Заполняем ключевые измерения и период для поиска записи
МенеджерЗаписи.Период = Дата("20171116");
МенеджерЗаписи.ПозицияШтатногоРасписания = СсылкаНаПозицию;

МенеджерЗаписи.Прочитать();

Если МенеджерЗаписи.Выбран() Тогда
    МенеджерЗаписи.УсловияТруда = Справочники.УсловияТруда.НайтиПоКоду("000000001");
    МенеджерЗаписи.Записать(Истина);
КонецЕсли;

Важные рекомендации по производительности и логике

← На главную