При разработке на платформе 1С часто возникает задача программного создания элементов справочников. Стандартный подход — скопировать существующий элемент, изменить необходимые реквизиты и записать новый объект. Однако в процессе можно столкнуться с ошибкой, которая на первый взгляд кажется нелогичной, особенно при работе с таким стандартным реквизитом, как «Код». Проанализируем типичную ситуацию и разберем все возможные причины возникновения ошибки.
Представим сценарий: разработчик пытается скопировать элемент справочника «ФизическиеЛица», присвоить ему новый уникальный код и записать. Вот пример кода, который приводит к проблеме:
&НаСервере
Процедура ДобавитьФизЛицоНаСервере()
НовыйОбъект = Объект.Ссылка.Скопировать();
НовыйОбъект.Код = "5555"; // На этой строке возникает ошибка
НовыйОбъект.Записать();
КонецПроцедуры
При выполнении этого кода система выдает исключение:
Поле объекта недоступно для записи (Кодо)
Давайте по шагам разберем, почему платформа не позволяет записать значение в, казалось бы, стандартное и доступное поле, и как это исправить.
Как ни странно, самая частая и неочевидная для начинающих разработчиков причина кроется не в коде, а в настройках самого объекта метаданных в конфигураторе.
Платформа «1С:Предприятие» позволяет гибко настраивать справочники. Одно из свойств справочника — длина кода. Если для справочника установлена длина кода, равная 0, это является для платформы прямым указанием: «этот справочник не использует коды». В таком случае поле для кода физически не создается в соответствующей таблице базы данных. Следовательно, любая попытка обратиться к реквизиту Код у объекта такого справочника приведет к ошибке, ведь вы пытаетесь записать данные в несуществующее поле.
Проверим и исправим эту ситуацию по шагам:
Справочники -> ФизическиеЛица).После этих действий реквизит Код станет доступен для записи, и исходный код выполнится без ошибок.
Хотя в рассмотренном случае проблема была именно в настройках справочника, похожая ошибка может возникать и по другим причинам. Рассмотрим их, чтобы вы могли проводить диагностику более эффективно.
В 1С важно четко различать два типа данных: ссылку (СправочникСсылка.ИмяСправочника) и объект (СправочникОбъект.ИмяСправочника).
В исходном коде автора ошибки нет, так как метод Скопировать() корректно возвращает именно СправочникОбъект, готовый к модификации и записи. Однако, если бы элемент получался другим способом, можно было бы совершить ошибку.
Посмотрим на неправильный пример:
// Неправильно! НайтиПоКоду() возвращает ССЫЛКУ, а не ОБЪЕКТ
НайденныйЭлемент = Справочники.Номенклатура.НайтиПоКоду("00001");
// Эта строка вызовет ошибку "Поле объекта недоступно для записи",
// так как мы пытаемся изменить реквизит у ссылки
НайденныйЭлемент.Наименование = "Новое наименование";
Чтобы исправить такой код, необходимо сначала получить объект из найденной ссылки с помощью метода ПолучитьОбъект().
Правильный вариант:
НайденныйЭлементСсылка = Справочники.Номенклатура.НайтиПоКоду("00001");
// Проверяем, что ссылка не пустая
Если НЕ НайденныйЭлементСсылка.Пустая() Тогда
// Получаем ОБЪЕКТ из ссылки
ОбъектДляИзменения = НайденныйЭлементСсылка.ПолучитьОбъект();
// Теперь можно безопасно менять реквизиты
ОбъектДляИзменения.Наименование = "Новое наименование";
ОбъектДляИзменения.Записать();
КонецЕсли;
Всегда проверяйте, с каким типом данных вы работаете, прежде чем пытаться изменять реквизиты.
Иногда запись может быть заблокирована не на уровне платформы, а на уровне бизнес-логики, заложенной в конфигурацию. Например, в обработчиках событий ПередЗаписью() или ПриЗаписи() могут стоять проверки, которые при определенных условиях запрещают изменение тех или иных реквизитов.
Для диагностики таких ситуаций существует мощный инструмент — режим ОбменДанными.Загрузка. Установка этого свойства в Истина позволяет временно отключить большинство проверок бизнес-логики при записи объекта.
Что отключает режим ОбменДанными.Загрузка = Истина:
Если ОбменДанными.Загрузка Тогда Возврат;).Как это использовать для отладки:
НовыйОбъект = Объект.Ссылка.Скопировать();
НовыйОбъект.Код = "5555";
// Включаем режим обмена
ОбменДанными.Загрузка = Истина;
Попытка
НовыйОбъект.Записать();
Исключение
// Если ошибка все равно есть, значит, проблема не в бизнес-логике
Сообщить(ОписаниеОшибки());
КонецПопытки;
// Обязательно выключаем режим после использования
ОбменДанными.Загрузка = Ложь;
Важно понимать: в нашем исходном случае с нулевой длиной кода этот режим не помог бы. ОбменДанными.Загрузка обходит логику, написанную программистами в конфигурации, но он не может обойти ограничения самой платформы, такие как попытка записи в несуществующее поле базы данных.
Проанализировав ситуацию, мы можем составить четкий алгоритм действий при возникновении ошибки «Поле объекта недоступно для записи» при работе с кодом справочника:
НайтиПоКоду, НайтиПоНаименованию), не забудьте вызвать метод .ПолучитьОбъект() перед изменением данных.НовыйОбъект). Это должен быть СправочникОбъект.ОбменДанными.Загрузка = Истина. Если запись пройдет успешно, значит, ищите проблему в обработчиках событий ПередЗаписью() и ПриЗаписи() модуля объекта.Следуя этим шагам, вы сможете быстро диагностировать и устранить причину ошибки, сэкономив время на отладку.