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

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

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

Анализ исходной проблемы: почему код не работает

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

Основные ошибки в исходном подходе:

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

Решение проблемы: правильный переход на сервер

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

Пример реализации простой процедуры удаления:


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

В клиентском коде вызов будет выглядеть следующим образом:


Для Каждого ЭлементДок из ИскомыеДоки Цикл
    // ... логика печати ...
    Если ТолькоПечать Тогда
        УдалитьДокументНаСервере(ЭлементДок);
    КонецЕсли;
КонецЦикла;

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

Если наша обработка или форма содержит много данных (реквизитов, табличных частей), каждый вызов процедуры &НаСервере будет передавать все состояние формы на сервер и обратно. Это создает лишнюю нагрузку на сеть. Чтобы этого избежать, рассмотрим использование директивы &НаСервереБезКонтекста. В этом случае на сервер уйдет только передаваемая ссылка, что значительно ускорит работу.


&НаСервереБезКонтекста
Процедура УдалитьДокументБезКонтекста(СсылкаНаДокумент)
    ДокОбъект = СсылкаНаДокумент.ПолучитьОбъект();
    Если ДокОбъект <> Неопределено Тогда
        ДокОбъект.Удалить();
    КонецЕсли;
КонецПроцедуры

Пакетное удаление для высокой производительности

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

Пример пакетного удаления:


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

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

Непосредственное удаление против пометки на удаление

Выясним разницу между методами. Метод Удалить() производит физическое удаление записи из таблицы базы данных. Это действие необратимо. Если на документ есть ссылки в других объектах (например, в регистрах сведений или других документах), в базе появятся записи с текстом "<Объект не найден>".

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

Риски автоматического удаления после печати

Проанализируем технологическую цепочку. Команда УправлениеПечатьюКлиент.ВыполнитьКомандуПечатиНаПринтер отправляет документ в спулер операционной системы Windows. Важно понимать, что 1С считает задачу выполненной в тот момент, когда данные переданы драйверу принтера. Если после этого в принтере зажует бумагу или кончится тонер, документ в 1С уже будет удален, и распечатать его повторно без восстановления данных (или перезапуска формирования) будет невозможно.

Совет: Если документы важны для учета, лучше не удалять их физически, а просто скрывать из видимости пользователя с помощью фильтров или устанавливать специальный статус «Архивный».

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

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


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

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

← На главную