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

Программист 1С v8.3 (Обычные формы) 1C:Бухгалтерия Бухгалтерский учет
← На главную

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

Причина №1: Попытка изменения выборки запроса

Рассмотрим ситуацию: вы выполнили запрос к регистру Хозрасчетный, получили объект ВыборкаИзРезультатаЗапроса и пытаетесь в цикле перезаписать поле Счет. Проанализируем, почему код ниже не будет работать:


Пока Выборка.Следующий() Цикл
    Если Выборка.Счет = Счет9001_04Ссылка Тогда
         Выборка.Счет = Счет9002_04Объект; // Ошибка здесь!
    КонецЕсли;
КонецЦикла;

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

Решение: Использование Таблицы Значений

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

  1. Выполним запрос и выгрузим результат методом Выгрузить().
  2. Добавим в таблицу новую колонку, если нужно хранить измененные данные, или будем редактировать существующие строки.
  3. Обойдем таблицу в цикле Для Каждого.

Проанализируем пример кода:


ТЗ = Запрос.Выполнить().Выгрузить();
// Если мы хотим сохранить старый счет и добавить новый:
ТЗ.Колонки.Добавить("НовыйСчет", Новый ОписаниеТипов("ПланСчетовСсылка.Хозрасчетный"));

Для Каждого Стр Из ТЗ Цикл
    Если Стр.Счет = Счет9001_04Ссылка Тогда
        Стр.НовыйСчет = Счет9002_04Ссылка; 
    КонецЕсли;
КонецЦикла;

Важный момент: обратите внимание на использование ОписаниеТипов при добавлении колонки. Это гарантирует строгую типизацию данных в ТаблицеЗначений.

Причина №2: Путаница между Ссылкой и Объектом

Вторая распространенная ошибка связана с пониманием типов данных 1С. Часто программисты пытаются присвоить полю регистра (которое ожидает Ссылку) целый Объект. Выясним разницу:

Если вы написали СчетОбъект = СчетСсылка.ПолучитьОбъект(), а затем пытаетесь присвоить этот СчетОбъект полю СчетДт в проводке, система либо проигнорирует присваивание, либо выдаст ошибку. В регистрах всегда должны храниться только Ссылки.

Работа с набором записей регистра бухгалтерии

Когда мы определились с тем, какие данные нам нужны, их необходимо записать в регистр. Для этого используется объект НаборЗаписей. Рассмотрим подробнее правильный алгоритм модификации проводок существующего документа:


НаборЗаписейБУ = РегистрыБухгалтерии.Хозрасчетный.СоздатьНаборЗаписей();
// Устанавливаем отбор по регистратору (обязательно!)
НаборЗаписейБУ.Отбор.Регистратор.Установить(ДокументСсылка);
// Читаем текущие записи из базы
НаборЗаписейБУ.Прочитать();

Для Каждого ЗаписьБУ Из НаборЗаписейБУ Цикл
    // Ищем соответствие в нашей подготовленной Таблице Значений
    СтрокаНастроек = ТЗ.Найти(ЗаписьБУ.СубконтоДт1, "НоменклатурнаяГруппа");
    
    Если СтрокаНастроек <> Неопределено Тогда
        // Присваиваем именно ССЫЛКУ на новый счет
        ЗаписьБУ.СчетДт = СтрокаНастроек.НовыйСчет;
    КонецЕсли;
КонецЦикла;

// Записываем измененный набор в базу данных
НаборЗаписейБУ.Записать();

Важные нюансы при записи регистров

Разберем несколько критических моментов, о которых нельзя забывать при программном изменении проводок:

  1. Метод Прочитать(): Если вы создаете набор записей и не вызываете Прочитать(), то при вызове Записать() все существующие проводки этого документа будут удалены, а запишутся только те, что вы добавили в код. Всегда читайте набор, если ваша цель — частичное редактирование.
  2. Соответствие Субконто: При замене счета (например, с 90.01 на 90.02) важно помнить, что наборы субконто у этих счетов могут отличаться. Если вы просто замените СчетДт, но типы субконто на новом счете другие, данные могут «потеряться» или стать некорректными. Проверяйте структуру ВидыСубконто нового счета.
  3. Зацикливание: Если вы выполняете этот код внутри подписки на событие ПриЗаписи того же документа, будьте осторожны, чтобы не вызвать бесконечную рекурсию.

Итоги

Подводя итог, проанализируем последовательность действий для успешного решения задачи:

Во-первых, никогда не пытайтесь записывать данные напрямую в объект Выборка. Используйте ТаблицуЗначений или Массив для подготовки данных.

Во-вторых, четко разделяйте Ссылки и Объекты. В регистры пишем только ссылки.

В-третьих, при работе с регистрами бухгалтерии всегда используйте НаборЗаписей с установленным отбором по регистратору и не забывайте вызывать метод Записать() в конце всех манипуляций. Мы вместе разобрали основные причины ошибки Поле объекта недоступно для записи, и теперь вы сможете эффективно обходить это ограничение платформы.

← На главную