Как программно изменить и сохранить значение реквизита существующего контрагента в 1С?

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

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

Разбор типичной ошибки: СоздатьЭлемент() против ссылки

Проанализируем ситуацию, с которой столкнулся автор темы. Попытка использовать метод СоздатьЭлемент() для редактирования уже существующей записи в базе данных является в корне неверной. Рассмотрим, что происходит в коде:


// Ошибочный подход
ТелефонОбработки = Справочники.Контрагенты.СоздатьЭлемент();
ТелефонОбработки.Ссылка = Стр.Ссылка; // Ошибка: Свойство Ссылка доступно только для чтения

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

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

Правильное решение: использование метода ПолучитьОбъект()

Для того чтобы изменить данные существующего контрагента, нам необходимо из Ссылки (которая является лишь указателем на запись в БД) получить Объект (который является набором данных в оперативной памяти, доступным для записи). Рассмотрим исправленный и лаконичный код, который решает задачу:


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

В этом примере мы используем метод ПолучитьОбъект(). Он считывает все данные конкретного контрагента из базы данных и позволяет нам менять любые его реквизиты. После вызова метода Записать() платформа обновляет существующую запись в таблице справочника.

Оптимизация процесса: режим загрузки данных

Если мы планируем обрабатывать тысячи контрагентов, простая циклическая запись может существенно замедлить работу системы и вызвать блокировки. Для ускорения процесса массового обновления данных рекомендуется использовать свойство ОбменДанными.Загрузка. Проанализируем, как это работает:


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

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

Работа с контактной информацией в современных конфигурациях (БСП)

Выясним причину, по которой прямое изменение реквизита ОсновнойТелефон может быть недостаточно. В современных конфигурациях, таких как 1С:Бухгалтерия 3.0, УТ 11 или ERP, телефоны хранятся в специальных табличных частях или регистрах сведений (механизм БСП — Библиотека Стандартных Подсистем).

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


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

Этот метод автоматически выполнит следующие действия:

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

Проверка на наличие изменений

Чтобы избежать лишних обращений к базе данных и не раздувать журнал регистрации, перед записью всегда полезно проверить: а изменилось ли значение на самом деле? Посмотрим на пример реализации такой проверки:


Если ТекущийКонтрагент.ОсновнойТелефон <> Стр.НовыйНомерТелефона Тогда
    ТекущийКонтрагент.ОсновнойТелефон = Стр.НовыйНомерТелефона;
    ТекущийКонтрагент.Записать();
КонецЕсли;

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

Использование транзакций для надежности

При массовой обработке данных рекомендуется объединять записи в транзакции. Это гарантирует, что если в середине процесса произойдет сбой (например, выключится свет или пропадет связь с сервером), данные не останутся в «полуобновленном» состоянии. Проанализируем структуру кода с транзакцией:


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

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

← На главную