При программном заполнении или обновлении данных справочников разработчики часто сталкиваются с задачей добавления новых записей в табличные части. Однако попытка модифицировать табличную часть напрямую через найденную ссылку приводит к ошибке выполнения: «Объект недоступен для изменения» или «Метод объекта не обнаружен (ПолучитьОбъект)». Разберем по шагам, почему возникает такое поведение платформы и как правильно организовать программное заполнение табличных частей.
Проанализируем архитектуру работы с данными в платформе 1С:Предприятие. При поиске элемента (например, с помощью методов НайтиПоКоду или НайтиПоНаименованию) платформа возвращает тип СправочникСсылка. Если обратиться к табличной части через ссылку:
НайденнаяСсылка.МенеджерыПокупателя
мы получим коллекцию типа СправочникТабличнаяЧасть. Данная коллекция предназначена исключительно для чтения. У нее отсутствуют методы изменения данных, а попытка вызвать метод Добавить() или получить объект от самой табличной части приводит к исключительной ситуации.
Для модификации любых реквизитов или табличных частей необходимо перевести ссылку в объектный режим в оперативной памяти — получить тип СправочникОбъект с помощью метода ПолучитьОбъект(). Только у объекта табличная часть имеет тип ТабличнаяЧасть, поддерживающий добавление, удаление и редактирование строк с последующей записью в базу данных.
Рассмотрим базовую правильную схему добавления строки в табличную часть существующего элемента справочника:
Ссылка.ПолучитьОбъект().Добавить().Записать().Посмотрим на пример кода, реализующий данный алгоритм:
// 1. Поиск контрагента по коду
НайденнаяСсылка = Справочники.Контрагенты.НайтиПоКоду(Формат(База.CODE, "ЧГ=0"));
Если НайденнаяСсылка.Пустая() Тогда
Сообщить("Контрагент с кодом " + База.CODE + " не найден в базе данных.");
Иначе
// 2. Получение объекта для редактирования
КонтрагентОбъект = НайденнаяСсылка.ПолучитьОбъект();
// 3. Поиск ответственного пользователя
Ответственный = Справочники.Пользователи.НайтиПоНаименованию(База.User);
Если ЗначениеЗаполнено(Ответственный) Тогда
// 4. Добавление новой строки в табличную часть
НоваяСтрока = КонтрагентОбъект.МенеджерыПокупателя.Добавить();
НоваяСтрока.МенеджерПокупателя = Ответственный;
// 5. Запись изменений в базу
КонтрагентОбъект.Записать();
Иначе
Сообщить("Пользователь " + База.User + " не найден.");
КонецЕсли;
КонецЕсли;
Проанализируем распространенные недочеты, которые часто допускают начинающие разработчики при работе с коллекциями и циклами:
Объект). Это ухудшает читаемость кода и может вызывать конфликты контекста (в модулях форм Объект — это основной реквизит формы). Лучше использовать осмысленные имена: КонтрагентОбъект, СтрокаТЧ, ТекущийКонтрагент.Продолжить.Ссылка.ТабличнаяЧасть.ПолучитьОбъект() является ошибочной, так как метод ПолучитьОбъект() определен только для ссылок на элементы и группы справочников, но не для их табличных частей.Рассмотрим подробнее практики, которые помогут избежать ошибок при массовой загрузке данных:
Если НайденнаяСсылка.ЭтоГруппа Тогда
// Пропускаем группы, если табличная часть предназначена только для элементов
Продолжить;
КонецЕсли;
НайденнаяСтрока = КонтрагентОбъект.МенеджерыПокупателя.Найти(Ответственный, "МенеджерПокупателя");
Если НайденнаяСтрока = Неопределено Тогда
НоваяСтрока = КонтрагентОбъект.МенеджерыПокупателя.Добавить();
НоваяСтрока.МенеджерПокупателя = Ответственный;
КонецЕсли;
ОбменДанными.Загрузка = Истина. Это отключает избыточные проверки бизнес-логики и обработчики событий при записи:
КонтрагентОбъект.ОбменДанными.Загрузка = Истина;
КонтрагентОбъект.Записать();
Записать() целесообразно помещать в конструкцию Попытка ... Исключение, чтобы ошибка блокировки или валидации одного элемента не прерывала обработку всего файла или набора данных.