Как программно создать элементы справочника из табличной части документа в 1С

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

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

Анализ типичной ошибки: почему «Поле объекта не обнаружено»?

Рассмотрим ситуацию: у нас есть документ ПриходТоваров, в табличной части которого (допустим, ТабличнаяЧасть1) имеется строковый реквизит НовыйТовар. Начинающие разработчики часто пытаются обратиться к этому реквизиту напрямую через имя табличной части, используя код следующего вида:


Процедура ОбработкаПроведения(Отказ, РежимПроведения)
    СпрТовар = Справочники.Товары.СоздатьЭлемент();
    СпрТовар.Наименование = ТабличнаяЧасть1.НовыйТовар; // Ошибка здесь!
    СпрТовар.Записать();
КонецПроцедуры

При выполнении этого кода система выдаст ошибку: «Поле объекта не обнаружено (НовыйТовар)». Давайте выясним причину. Объект ТабличнаяЧасть1 является коллекцией (типа ДанныеФормыКоллекция или РезультатЗапроса, в зависимости от контекста), которая содержит множество строк. У самой коллекции нет реквизита НовыйТовар — этот реквизит есть только у каждой конкретной строки этой коллекции. Чтобы получить доступ к данным, нам необходимо перебрать все строки таблицы в цикле.

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

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

  1. Инициируем цикл Для Каждого... Из... Цикл для обращения к строкам табличной части.
  2. Внутри цикла создаем новый объект справочника методом СоздатьЭлемент().
  3. Присваиваем реквизитам справочника значения из текущей строки таблицы.
  4. Выполняем метод Записать() для сохранения данных в базе.

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


// Перебираем все строки табличной части документа
Для Каждого СтрокаТЧ Из ТабличнаяЧасть1 Цикл
    
    // Создаем новый объект справочника "Товары"
    НовыйЭлемент = Справочники.Товары.СоздатьЭлемент();
    
    // Заполняем наименование из строкового реквизита текущей строки
    НовыйЭлемент.Наименование = СтрокаТЧ.НовыйТовар;
    
    // Фиксируем изменения в базе данных
    НовыйЭлемент.Записать();
    
КонецЦикла;

Где лучше разместить этот код? Архитектурный подход

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

  1. Дублирование данных: При каждом перепроведении документа (например, если бухгалтер решил изменить дату или комментарий) цикл будет запускаться снова, создавая в справочнике дубликаты товаров с одинаковыми именами.
  2. Транзакционные риски: Проведение документа — это сложная транзакция, работающая с регистрами. Создание справочной информации внутри этой транзакции может привести к излишним блокировкам таблиц.
  3. Логическая несостыковка: Проведение документа предназначено для отражения движений по счетам и регистрам, а не для изменения структуры нормативно-справочной информации.

Рекомендуемые варианты размещения кода:

Проверка на дубликаты и оптимизация процесса

Чтобы не засорять базу данных повторяющимися элементами, перед созданием нового объекта необходимо проверить, не существует ли уже товар с таким наименованием. Для этого используем метод НайтиПоНаименованию() менеджера справочника.

Проанализируем улучшенный код с проверкой на существование:


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

Работа с большими объемами данных: Транзакции

Если в табличной части документа сотни или тысячи строк, запись каждого элемента по отдельности будет работать медленно, так как каждый вызов Записать() открывает и закрывает отдельную транзакцию в СУБД. В такой ситуации мы рекомендуем обернуть весь цикл в одну общую транзакцию. Это значительно ускорит процесс.

Рассмотрим пример использования механизмов транзакций:


НачатьТранзакцию();

Попытка
    Для Каждого СтрокаТЧ Из Объект.ТабличнаяЧасть1 Цикл
        // Логика поиска и создания элемента...
        // ...
    КонецЦикла;
    
    ЗафиксироватьТранзакцию();
    Сообщить("Справочник успешно обновлен.");
Исключение
    ОтменитьТранзакцию();
    Сообщить("Произошла ошибка, изменения не сохранены: " + ОписаниеОшибки());
КонецПопытки;

Важность ссылочной целостности

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

  1. Пользователь вводит текст в поле с типом СправочникСсылка.
  2. В обработчике АвтоПодбор или ОкончаниеВводаТекста система программно создает элемент справочника.
  3. В строку документа записывается уже готовая ссылка на объект.

Это обеспечит надежную связь между документами и справочниками. При простом хранении текста любая опечатка (лишний пробел или буква) приведет к тому, что отчеты не смогут правильно сгруппировать данные по товару. Использование объектов СправочникОбъект и СправочникСсылка — это фундамент правильной разработки на платформе 1С.

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

← На главную