В практике разработчика 1С нередко возникают задачи, когда необходимо сформировать временные документы, распечатать их и сразу же удалить из информационной базы, чтобы не загромождать справочники и реестры лишними данными. Однако при реализации такой логики начинающие программисты часто сталкиваются с ошибками контекста или методологии. В этой статье мы подробно разберем, как правильно реализовать удаление объектов, почему возникают ошибки типа «Метод объекта не обнаружен» и как оптимизировать процесс взаимодействия клиента и сервера.
Рассмотрим ситуацию, с которой столкнулся автор темы. В его коде на стороне клиента выполняется цикл по массиву ссылок на документы. После команды печати он пытается вызвать метод Удалить() непосредственно у элемента массива. Выясним причину неудачи: в переменной ЭлементДок хранится ссылка (тип ДокументСсылка), а метод Удалить() принадлежит объекту (тип ДокументОбъект). Более того, физическое удаление данных из базы — это серверная операция, которая недоступна на тонком клиенте.
Основные ошибки в исходном подходе:
ПолучитьОбъект().Для корректного удаления документа нам необходимо создать серверную процедуру, которая будет принимать ссылку на документ в качестве параметра. Проанализируем правильный алгоритм действий. Сначала мы передаем ссылку из клиентского цикла в серверный контекст, там преобразуем её в объект и вызываем метод удаления.
Пример реализации простой процедуры удаления:
&НаСервере
Процедура УдалитьДокументНаСервере(СсылкаНаДокумент)
// Извлекаем объект из базы данных по ссылке
ОбъектДокумента = СсылкаНаДокумент.ПолучитьОбъект();
// Проверяем, что объект существует (не был удален ранее)
Если ОбъектДокумента <> Неопределено Тогда
// Выполняем непосредственное удаление без пометки на удаление
ОбъектДокумента.Удалить();
КонецЕсли;
КонецПроцедуры
В клиентском коде вызов будет выглядеть следующим образом:
Для Каждого ЭлементДок из ИскомыеДоки Цикл
// ... логика печати ...
Если ТолькоПечать Тогда
УдалитьДокументНаСервере(ЭлементДок);
КонецЕсли;
КонецЦикла;
Если наша обработка или форма содержит много данных (реквизитов, табличных частей), каждый вызов процедуры &НаСервере будет передавать все состояние формы на сервер и обратно. Это создает лишнюю нагрузку на сеть. Чтобы этого избежать, рассмотрим использование директивы &НаСервереБезКонтекста. В этом случае на сервер уйдет только передаваемая ссылка, что значительно ускорит работу.
&НаСервереБезКонтекста
Процедура УдалитьДокументБезКонтекста(СсылкаНаДокумент)
ДокОбъект = СсылкаНаДокумент.ПолучитьОбъект();
Если ДокОбъект <> Неопределено Тогда
ДокОбъект.Удалить();
КонецЕсли;
КонецПроцедуры
Рассмотрим ситуацию, когда документов для удаления много (например, сотни или тысячи). Вызов сервера для каждого отдельного документа в цикле — это неэффективно. Проанализируем, как можно оптимизировать этот процесс. Правильным подходом будет сбор всех ссылок в один массив и передача этого массива на сервер для удаления в одном транзакционном цикле.
Пример пакетного удаления:
&НаСервереБезКонтекста
Процедура УдалитьМассивДокументовНаСервере(МассивСсылок)
Для Каждого ТекущаяСсылка Из МассивСсылок Цикл
Объект = ТекущаяСсылка.ПолучитьОбъект();
Если Объект <> Неопределено Тогда
// Используем ОбменДанными.Загрузка, чтобы отключить лишние проверки в модуле объекта
Объект.ОбменДанными.Загрузка = Истина;
Объект.Удалить();
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Важный нюанс: Использование свойства ОбменДанными.Загрузка = Истина позволяет ускорить удаление, так как платформа проигнорирует прикладные проверки в процедурах ПередУдалением или ПриУдалении, которые могут быть прописаны в модуле документа.
Выясним разницу между методами. Метод Удалить() производит физическое удаление записи из таблицы базы данных. Это действие необратимо. Если на документ есть ссылки в других объектах (например, в регистрах сведений или других документах), в базе появятся записи с текстом "<Объект не найден>".
Альтернативный и более безопасный способ — использование метода УстановитьПометкуУдаления(Истина). В этом случае документ останется в базе, но будет помечен как недействительный. Его можно будет окончательно удалить позже через стандартную обработку «Удаление помеченных объектов», которая автоматически проверит наличие ссылок на этот документ и предотвратит нарушение целостности данных.
Проанализируем технологическую цепочку. Команда УправлениеПечатьюКлиент.ВыполнитьКомандуПечатиНаПринтер отправляет документ в спулер операционной системы Windows. Важно понимать, что 1С считает задачу выполненной в тот момент, когда данные переданы драйверу принтера. Если после этого в принтере зажует бумагу или кончится тонер, документ в 1С уже будет удален, и распечатать его повторно без восстановления данных (или перезапуска формирования) будет невозможно.
Совет: Если документы важны для учета, лучше не удалять их физически, а просто скрывать из видимости пользователя с помощью фильтров или устанавливать специальный статус «Архивный».
При массовой работе с данными всегда стоит помнить о целостности. Разберем, как гарантировать, что либо все документы будут удалены, либо (в случае ошибки) ни один из них не пропадет. Для этого мы обернем наш цикл удаления в транзакцию.
&НаСервереБезКонтекста
Процедура БезопасноеУдаление(МассивСсылок)
НачатьТранзакцию();
Попытка
Для Каждого Ссылка Из МассивСсылок Цикл
// Логика удаления...
КонецЦикла;
ЗафиксироватьТранзакцию();
Исключение
ОтменитьТранзакцию();
ЗаписатьЛогСобытий("Ошибка при массовом удалении: " + ОписаниеОшибки());
ВызватьИсключение; // Передаем ошибку дальше на клиент
КонецПопытки;
КонецПроцедуры
Подводя итог, отметим, что ключ к решению любой задачи по манипуляции данными в 1С — это четкое понимание того, в каком контексте (клиент или сервер) выполняется код и с каким типом данных (ссылка или объект) вы работаете в данный момент.