Как программно удалить или пометить на удаление элемент справочника в 1С?

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

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

Разбор основной проблемы: почему нельзя удалить элемент прямо из выборки

Рассмотрим типичную ситуацию: у нас есть справочник Задание1, и нам нужно удалить все элементы, цена которых превышает 10 000. Типичная ошибка новичка выглядит так:


// ОШИБОЧНЫЙ КОД
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
    Справочники.Задание1.Удалить(Выборка); // Ошибка!
КонецЦикла;

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

Шаг 1: Правильная подготовка запроса

Прежде чем приступать к удалению, проанализируем структуру нашего запроса. Чтобы иметь возможность программно воздействовать на элемент справочника, мы обязательно должны выбрать поле Ссылка. Без ссылки мы не сможем получить доступ к объекту в памяти сервера.

Рассмотрим правильный текст запроса:


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |   Задание1.Ссылка КАК Ссылка,
    |   Задание1.Цена КАК Цена
    |ИЗ
    |   Справочник.Задание1 КАК Задание1
    |ГДЕ
    |   Задание1.Цена > &ПорогЦены";

Запрос.УстановитьПараметр("ПорогЦены", 10000);
РезультатЗапроса = Запрос.Выполнить();
ВыборкаДетальныеЗаписи = РезультатЗапроса.Выбрать();

Обратим внимание на использование условия ГДЕ в тексте запроса. Проанализируем ситуацию: гораздо эффективнее отобрать нужные строки сразу средствами СУБД, чем выбирать все записи и проверять условие Если Цена > 10000 Тогда внутри цикла в коде 1С. Это значительно экономит ресурсы сервера.

Шаг 2: Выбор метода — удаление или пометка?

В 1С существует два способа исключения элемента из работы: непосредственное удаление и установка пометки удаления. Выясним причину, почему второй вариант считается более безопасным.

Вариант А: Установка пометки на удаление (рекомендуется)

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

Разберем по шагам, как это сделать в цикле:


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

Вариант Б: Непосредственное программное удаление

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


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

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

Шаг 3: Оптимизация процесса (режим «Загрузка»)

Проанализируем ситуацию, когда элементов очень много (десятки тысяч). При вызове УстановитьПометкуУдаления() или Удалить() 1С запускает все стандартные проверки, прописанные в модуле объекта (события ПередЗаписью, ПриЗаписи и т.д.). Это может сильно замедлить работу.

Чтобы ускорить процесс, мы можем использовать свойство ОбменДанными.Загрузка. Это скажет системе, что мы выполняем технологическую операцию и прикладные проверки выполнять не нужно.


МОбъект = ВыборкаДетальныеЗаписи.Ссылка.ПолучитьОбъект();
МОбъект.ОбменДанными.Загрузка = Истина; 
МОбъект.Удалить(); // Или УстановитьПометкуУдаления

Шаг 4: Безопасность и контроль (Транзакции и Ссылки)

Рассмотрим подробнее вопросы безопасности. Если в процессе массового удаления произойдет сбой (например, выключится свет или пропадет связь с сервером), часть объектов окажется удалена, а часть — нет. Для обеспечения целостности операции мы должны использовать транзакцию.

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

Посмотрим на комплексный пример кода:


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

Итоги и рекомендации

Мы выяснили, что для программного удаления строки в справочнике недостаточно просто вызвать метод. Необходимо соблюдать последовательность действий:

  1. Подготовить запрос, в котором обязательно выбирается поле Ссылка.
  2. Определить способ исключения: физическое удаление (Удалить()) или логическое (УстановитьПометкуУдаления()).
  3. Получить объект через Ссылка.ПолучитьОбъект().
  4. Обернуть код в попытку-исключение, чтобы избежать аварийной остановки программы.
  5. Использовать транзакции для массовых операций, чтобы гарантировать целостность данных.

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

← На главную