При разработке в среде 1С:Предприятие, особенно на этапе обучения, программисты часто сталкиваются с ситуацией, когда попытка заполнить данными табличную часть документа или обработки вызывает ошибку «Поле объекта недоступно для записи». Рассмотрим подробно, почему возникает эта проблема, разберем механику работы коллекций в 1С и выясним, как правильно выгружать результаты запроса в интерфейсные элементы.
Разберем ситуацию на примере кода, представленного в обсуждении. Программист выполняет сложный запрос, получает таблицу значений и пытается записать её в переменную, имя которой совпадает с именем табличной части на форме:
ЗакрытыеЗаказы = Запрос.Выполнить().Выгрузить();
С точки зрения логики обычного программирования (например, в языках с динамической типизацией), это выглядит корректно: мы берем один объект и заменяем его другим. Однако в 1С табличная часть объекта (документа, справочника или обработки) — это не просто переменная, а неизменяемая ссылка на коллекцию строк.
Проанализируем ситуацию глубже: когда платформа создает объект в памяти, она жестко резервирует место под его табличные части в соответствии с метаданными, заданными в конфигураторе. Прямое присваивание ЗакрытыеЗаказы = ... означает попытку «отвязать» встроенную таблицу от объекта и подставить на её место совершенно новую таблицу значений из памяти. Система безопасности платформы блокирует это действие, выдавая ошибку доступа на запись, так как структура объекта должна оставаться целостной.
Для того чтобы обновить содержимое табличной части, не нарушая целостность объекта, следует использовать штатный метод коллекции — Загрузить(). Этот метод не меняет саму ссылку на таблицу, а выполняет две последовательные операции: очищает текущие строки и наполняет таблицу данными из переданного источника (другой таблицы значений).
Рассмотрим правильный алгоритм действий:
Загрузить() у целевой табличной части.Пример исправленного кода:
// 1. Получаем данные во временную ТЗ
ТЗ_Результат = Запрос.Выполнить().Выгрузить();
// 2. Загружаем данные в табличную часть объекта
ЭтотОбъект.ЗакрытыеЗаказы.Загрузить(ТЗ_Результат);
Обратите внимание на использование обращения ЭтотОбъект (в обычных формах) или Объект (в управляемых формах). Это позволяет явно указать системе, что мы работаем с реквизитом текущего контекста, исключая конфликты с локальными переменными, которые могут иметь схожие имена.
Часто после исправления ошибки «недоступно для записи» программист сталкивается со следующей проблемой: код выполняется без ошибок, но табличная часть остается пустой или заполняется частично. Проанализируем причину в сообщении №10 из темы: «остаётся пустая колонка КоличествоНепринятых».
Метод Загрузить() работает по принципу соответствия имен. Данные будут перенесены из таблицы-источника в таблицу-приемник только в том случае, если имена колонок совпадают символ в символ (с учетом регистра).
Рассмотрим, как правильно сопоставлять поля в запросе:
Запрос.Текст =
"ВЫБРАТЬ
| Регион КАК Регион,
| ЗаказПоставщику КАК ЗаказПоставщику,
| СуммаДокумента КАК СуммаЗаказа // Имя в запросе должно совпадать с именем колонки в ТЧ
| ИЗ
| Документ.ЗакрытиеЗаказовПоставщикам";
Если в конфигураторе колонка табличной части называется СуммаЗаказа, а в запросе вы написали СуммаДокумента без псевдонима (КАК), то метод Загрузить() просто проигнорирует эти данные, так как не найдет цели для вставки. Всегда проверяйте вкладку «Колонки» у табличной части в дереве метаданных.
При выполнении соединений в запросах (особенно ЛЕВОЕ СОЕДИНЕНИЕ) поля могут содержать значение NULL. Если колонка вашей табличной части имеет числовой тип, загрузка NULL может привести к тому, что в ячейке будет пусто.
Проанализируем, как избежать этой ситуации с помощью функции ЕСТЬNULL:
Запрос.Текст =
"ВЫБРАТЬ
| ЕСТЬNULL(ВложенныйЗапрос.Количество, 0) КАК Количество,
| ЕСТЬNULL(ВложенныйЗапрос.СуммаЗаказа, 0) КАК СуммаЗаказа
| ИЗ ...";
Это гарантирует, что даже при отсутствии данных в таблицу попадет корректное числовое значение (ноль), что важно для последующих вычислений или итогов в подвале формы.
В контексте обсуждения упоминается работа с обычными формами (Message 9). Это упрощает задачу, так как код выполняется непосредственно в модуле формы, где доступ к объекту прямой. Однако полезно помнить о различиях:
В обычных формах: мы работаем с данными напрямую через ЭтотОбъект.ИмяТЧ. Если табличная часть является реквизитом самой формы (не объекта), обращение идет просто по имени.
В управляемых формах: работа ведется с данными через структуру Объект. Если код выполняется на стороне сервера, мы используем Объект.ЗакрытыеЗаказы.Загрузить(ТЗ). Если же нам нужно преобразовать данные между прикладным объектом и данными формы, используются методы РеквизитФормыВЗначение и ЗначениеВРеквизитФормы, хотя для простой загрузки в Объект на сервере они чаще всего не требуются.
Подведем итог и составим пошаговый план решения проблемы:
=.ТЗ = Запрос.Выполнить().Выгрузить();).ИмяТабличнойЧасти.Загрузить(ТЗ);.КАК) с именами колонок в конфигураторе.ИмяТабличнойЧасти.Очистить();, хотя метод Загрузить() сделает это автоматически.Соблюдение этих правил избавит вас от ошибок доступа и гарантирует корректное отображение данных в интерфейсе программы 1С.