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

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

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

Анализ исходной проблемы

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


Запрос = Новый Запрос;
Запрос.Текст = "
|ВЫБРАТЬ
|    Сотрудники.Ссылка КАК Сотрудник,
|    Сотрудники.Должность.Наименование КАК Должность
|ИЗ
|    Справочник.Сотрудники КАК Сотрудники";
Выборка = Запрос.Выполнить().Выбрать();
СотрудникВ = "Иванов";
ДолжностьВ = "водитель";
Пока Выборка.Следующий() Цикл
    Если Выборка.Сотрудник = СотрудникВ Тогда
        Выборка.Должность = ДолжностьВ; // ОШИБКА ЗДЕСЬ
    КонецЕсли;
КонецЦикла;

Выясним причину ошибки. Объект ВыборкаИзРезультатаЗапроса предназначен исключительно для чтения данных. Когда мы выполняем запрос, система формирует временную таблицу в памяти, которая является «снимком» состояния базы данных на момент выполнения запроса. Поля этой таблицы доступны только для получения значений. Попытка присвоить новое значение свойству Выборка.Должность логично приводит к отказу системы, так как у объекта выборки нет механизмов для обратной записи данных в базу.

Решение 1: Получение объекта через ссылку в выборке

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

Рассмотрим правильный алгоритм действий в цикле:

  1. Получаем ссылку на элемент справочника из выборки.
  2. Используем метод ПолучитьОбъект(), чтобы перевести данные из состояния «только чтение» в состояние «редактирование».
  3. Изменяем нужный реквизит.
  4. Вызываем метод Записать(), чтобы зафиксировать изменения в базе данных.

Посмотрим на пример исправленного кода:


Пока Выборка.Следующий() Цикл
    // Сравниваем ссылку с искомым значением (лучше сравнивать Ссылки, а не строки)
    Если Выборка.Сотрудник.Наименование = СотрудникВ Тогда 
        // Получаем объект для редактирования
        СотрудникОбъект = Выборка.Сотрудник.ПолучитьОбъект();
        
        // Устанавливаем новое значение (ссылку на элемент справочника Должности)
        СотрудникОбъект.Должность = НоваяДолжностьСсылка; 
        
        // Обязательно записываем объект
        СотрудникОбъект.Записать();
    КонецЕсли;
КонецЦикла;

Решение 2: Прямой поиск и изменение (ученический метод)

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


// 1. Находим ссылку на сотрудника по его имени
СотрудникСсылка = Справочники.Сотрудники.НайтиПоНаименованию("Иванов");

// 2. Проверяем, найден ли сотрудник (не является ли ссылка пустой)
Если Не СотрудникСсылка.Пустая() Тогда
    // 3. Получаем объект для изменения
    СотрудникОбъект = СотрудникСсылка.ПолучитьОбъект();
    
    // 4. Находим ссылку на новую должность
    НоваяДолжность = Справочники.Должности.НайтиПоНаименованию("водитель");
    
    // 5. Присваиваем и записываем
    СотрудникОбъект.Должность = НоваяДолжность;
    СотрудникОбъект.Записать();
КонецЕсли;

Важное замечание: Этот метод прост для понимания, но имеет ряд серьезных ограничений, которые мы проанализируем ниже.

Почему поиск по наименованию — плохая практика?

В реальных информационных системах использование метода НайтиПоНаименованию считается «дурным тоном» и потенциальным источником ошибок. Рассмотрим причины:

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

Разница между Справочником и Регистром сведений

В профессиональных конфигурациях, таких как ЗУП или ERP, должность сотрудника крайне редко хранится простым реквизитом в справочнике Сотрудники. Чаще всего используется периодический регистр сведений (например, «Кадровая история сотрудников»).

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

В таких случаях вместо СотрудникОбъект.Записать() необходимо:

  1. Либо создавать документ Кадровый перевод и проводить его.
  2. Либо программно создавать запись в регистре сведений с указанием Периода (даты назначения на должность).

Оптимизация: Блокировки и Транзакции

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

Перед вызовом ПолучитьОбъект() в высоконагруженных системах рекомендуется явно заблокировать данные. Кроме того, если вы вносите несколько связанных изменений (например, меняете должность и оклад), объединяйте их в транзакцию:


НачатьТранзакцию();
Попытка
    СотрудникОбъект = ВыбраннаяСсылка.ПолучитьОбъект();
    СотрудникОбъект.Заблокировать(); // Блокируем от изменений другими пользователями
    
    СотрудникОбъект.Должность = НоваяДолжность;
    // ... другие изменения ...
    
    СотрудникОбъект.Записать();
    ЗафиксироватьТранзакцию();
Исключение
    ОтменитьТранзакцию();
    Сообщить("Не удалось изменить данные: " + ОписаниеОшибки());
КонецПопытки;

Резюме по работе с объектами

Подведем итог нашему исследованию. Для корректного изменения данных в 1С необходимо соблюдать следующие правила:

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

← На главную