Как программно изменить реквизиты справочника через табличную часть документа или обработки?

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

В процессе разработки на платформе 1С:Предприятие часто возникает задача массового изменения данных. Типичный сценарий: у нас есть документ или внешняя обработка с табличной частью, в которой указаны ссылки на элементы справочника (например, СерииНоменклатуры). Нам нужно изменить какой-либо реквизит внутри этих элементов (например, дату ГоденДо). Рассмотрим, почему простые попытки присвоить значение «через точку» не работают и как правильно реализовать эту логику.

Разбор основной ошибки: Ссылка vs Объект

Проанализируем типичную ситуацию, с которой сталкиваются новички. При попытке выполнить код вида СтрокаТЧ.Серия.ГоденДо = НоваяДата; система выдает ошибку: «Поле объекта недоступно для записи». Выясним причину: в табличной части хранится Ссылка (тип СправочникСсылка.СерииНоменклатуры). Ссылка — это всего лишь уникальный идентификатор записи в базе данных, она предназначена для чтения и поиска, но не для редактирования.

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

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

Реализация записи данных в справочник через цикл

Рассмотрим подробнее программный код, который позволяет обойти строки табличной части и обновить данные в связанном справочнике. Предположим, у нас есть обработка, где в шапке указан новый СрокГодности, а в табличной части Инфо перечислены серии.


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

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

Синхронное обновление справочника и табличной части документа

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


// 1. Получаем объект документа, который выбрали в обработке
ДокОбъект = Объект.СсылкаНаДокумент.ПолучитьОбъект();

// 2. Перебираем строки документа
Для Каждого СтрокаДок Из ДокОбъект.Товары Цикл
    
    // Обновляем справочник Серии
    Если ЗначениеЗаполнено(СтрокаДок.Серия) Тогда
        ОбъектСерии = СтрокаДок.Серия.ПолучитьОбъект();
        ОбъектСерии.ГоденДо = Объект.НовыйСрокГодности;
        ОбъектСерии.Записать();
    КонецЕсли;
    
    // Обновляем реквизит в самой строке документа
    СтрокаДок.ГоденДо = Объект.НовыйСрокГодности;
    
КонецЦикла;

// 3. Записываем сам документ
ДокОбъект.Записать(РежимЗаписиДокумента.Запись);

Оптимизация: работа с уникальными ссылками

Рассмотрим ситуацию, когда в документе на 1000 строк используется всего 5 уникальных серий. Если мы будем вызывать ПолучитьОбъект() и Записать() в каждой строке, мы выполним 1000 обращений к базе данных вместо 5. Это критически замедляет работу системы. Проанализируем, как оптимизировать этот процесс с помощью соответствия (коллекция Соответствие).


// Создаем коллекцию для хранения уже обработанных серий
ОбработанныеСерии = Новый Соответствие;

Для Каждого Стр Из Объект.Инфо Цикл
    
    СсылкаНаСерию = Стр.Серия;
    
    // Если мы еще не записывали эту серию в данном цикле
    Если ОбработанныеСерии[СсылкаНаСерию] = Неопределено Тогда
        
        ОбъектСерии = СсылкаНаСерию.ПолучитьОбъект();
        ОбъектСерии.ГоденДо = Объект.СрокГодности;
        ОбъектСерии.Записать();
        
        // Помечаем серию как обработанную
        ОбработанныеСерии.Вставить(СсылкаНаСерию, Истина);
        
    КонецЕсли;
    
КонецЦикла;

Такой подход сокращает количество транзакций и значительно повышает производительность обработки данных.

Важные аспекты безопасности и целостности данных

При программном изменении данных всегда следует учитывать контекст выполнения и бизнес-логику системы. Разберем ключевые рекомендации:

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

← На главную