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