Почему не записываются данные в справочник 1С при программном изменении

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

Рассмотрим распространенную и коварную ситуацию при разработке в платформе 1С: программный код внешне отрабатывает абсолютно успешно, отладчик проходит по строкам с вызовом метода Записать(), исключений и ошибок в интерактивном режиме не возникает, однако при открытии формы элемента или списка справочника измененные данные отсутствуют.

С подобной ситуацией часто сталкиваются программисты при создании обработок загрузки номенклатуры, контрагентов или прайс-листов из внешних файлов (Excel, CSV, XML). Проанализируем причины такого поведения платформы 1С и разберем, как правильно выстроить работу с транзакциями и записью объектов.

Анализ проблемы: неявный откат транзакции в 1С

Выясним главную причину, по которой модифицированный или созданный объект справочника (например, СправочникОбъект.Номенклатура) не сохраняет внесенные изменения в физических таблицах базы данных. В платформе 1С манипуляции с данными происходят в рамках механизмов СУБД, управлением которыми выступают транзакции.

Если в коде обработки вызывается метод НачатьТранзакцию(), платформа открывает явную транзакцию. В случае, если до выхода из процедуры или функции не был явным образом вызван метод ЗафиксироватьТранзакцию(), платформа 1С автоматически выполняет неявный откат (ROLLBACK) всех изменений, произведенных в базе данных с момента старта транзакции. При этом метод Записать() объекта отрабатывает без вызова ошибки в точке выполнения, так как на момент вызова оператора запись во временный контекст транзакции прошла успешно.

Разбор практического примера: загрузка номенклатуры из Excel

Проанализируем фрагмент кода, содержащий эту распространенную ошибку. Код выполняет чтение таблицы Excel через COM-объект, заполняет локальную таблицу значений и обновляет данные элементов справочника Номенклатура.

Посмотрим на ошибочный вариант построения процедуры:


// Открываем COM-соединение с Excel
Excel = Новый COMОбъект("Excel.Application"); 
ОткрытьФайл = Excel.WorkBooks.Open(ПутьКФайлу);
ОткрытьФайл = ОткрытьФайл.WorkSheets(1);

xlCellTypeLastCell = 11;
ExcelПоследняяСтрока = ОткрытьФайл.Cells.SpecialCells(xlCellTypeLastCell).Row;

ТзД = Новый ТаблицаЗначений;
ТзД.Колонки.Добавить("КодИнструмента");
ТзД.Колонки.Добавить("Инструмент");

// ОШИБКА: Открываем транзакцию перед циклом чтения
НачатьТранзакцию(); 

Для Строка = 2 По ExcelПоследняяСтрока Цикл
    СтрокаТ = ТзД.Добавить();
    СтрокаТ.КодИнструмента = СокрЛП(ОткрытьФайл.Cells(Строка,1).Value); 
    СтрокаТ.Инструмент = СокрЛП(ОткрытьФайл.Cells(Строка,4).Value); 
КонецЦикла;

Excel.WorkBooks.Close();
Excel.Quit();

// Попытка модифицировать номенклатуру
л_Ном = Справочники.Номенклатура.НайтиПоКоду("72458");
Если Не л_Ном.Пустая() Тогда
    Ном = л_Ном.ПолучитьОбъект();              
    СтрокаНом = Ном.ТорговыеНазвания.Добавить();
    СтрокаНом.Номенклатура = л_Ном; 
    Ном.Записать(); // Метод отработает, но изменения откатятся!
КонецЕсли;

// ОШИБКА: ЗафиксироватьТранзакцию() отсутствуют в конце процедуры!

В приведенном выше примере метод НачатьТранзакцию() был случайно скопирован при вставке кода чтения файла. Из-за отсутствия ЗафиксироватьТранзакцию() в конце процедуры все записи объектов, выполненные методом Ном.Записать(), были аннулированы платформой сразу после завершения выполнения процедуры.

Канонический шаблон работы с транзакциями в 1С

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


НачатьТранзакцию();
Попытка
    Для Каждого СтрокаТ Из ТзД Цикл
        л_Код = СокрЛП(СтрЗаменить(СтрокаТ.КодИнструмента, Символы.НПП, ""));
        Если ПустаяСтрока(л_Код) Тогда
            Продолжить;
        КонецЕсли;

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

        // Изменение существующего объекта
        л_Объект = л_Номенклатура.ПолучитьОбъект();
        л_Объект.НаименованиеПолное = СокрЛП(л_Объект.Наименование);
        
        // Модификация табличной части
        НоваяСтрока = л_Объект.ТорговыеНазвания.Добавить();
        НоваяСтрока.Номенклатура = л_Номенклатура;

        // Фиксируем изменения конкретного объекта
        л_Объект.Записать();
    КонецЦикла;

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

Полезные методы диагностики и отладки

Рассмотрим дополнительные инструменты и подходы, которые помогают быстро диагностировать проблемы при программном изменении элементов справочников:

  1. Проверка активности транзакции: С помощью функции ТранзакцияАктивна() можно проверить, находится ли исполняемый код внутри незавершенного транзакционного блока. Это предотвращает случайное создание незафиксированных транзакций.
  2. Режим загрузки данных: Если необходимо записать объект в обход стандартных проверок модуля объекта и подписок на события (например, при первоначальной загрузке), используйте свойство ОбменДанными.Загрузка:
    
    л_Объект = л_Ссылка.ПолучитьОбъект();
    л_Объект.ОбменДанными.Загрузка = Истина;
    л_Объект.Записать();
    
  3. Корректное завершение COM-процессов: При работе с файлами Excel через COM обязательно завершайте сеанс методами Excel.Quit() и обнуляйте переменную Excel = Неопределено, чтобы процесс EXCEL.EXE не оставался в оперативной памяти сервера или клиента.
  4. Обновление интерфейса: Если данные записываются программно, но пользователь не видит изменений в открытых формах или динамических списках, примените глобальный метод ОповеститьОбИзменении(СсылкаНаОбъект) для принудительного обновления кэша форм.
← На главную