Почему не очищается набор записей регистра сведений в 1С и как это исправить?

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

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

Канонический способ очистки набора записей по отбору

Проанализируем исходный код, который часто пишут начинающие разработчики:


НЗ = РегистрыСведений.ПРОФИТ_Обеспечения.СоздатьНаборЗаписей();
НЗ.Отбор.Договор.Значение = СвязанныйДоговор;
НЗ.Отбор.Договор.ВидСравнения = ВидСравнения.Равно;
НЗ.Отбор.Договор.Использование = Истина;
НЗ.Прочитать();
НЗ.Очистить();
НЗ.Записать(Истина);

В этом фрагменте допущены лишние действия, которые не влияют на результат, но перегружают код и серверную базу лишними запросами:

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

Посмотрим на корректный, лаконичный и быстрый вариант кода для удаления записей по измерению:


НЗ = РегистрыСведений.ПРОФИТ_Обеспечения.СоздатьНаборЗаписей();
НЗ.Отбор.Договор.Установить(СвязанныйДоговор);
НЗ.Записать();

В метод Записать() по умолчанию передается параметр Замещать = Истина. Так как в наборе отсутствуют строки, платформа заменяет имеющиеся в базе данные по договору пустым набором — то есть полностью их удаляет.

Основная причина: влияние обработчиков событий и подписок

Если синтаксически код написан верно, ошибок при выполнении не возникает, но данные в регистре остаются, выясним причину такого поведения. Как показала практика, чаще всего дело заключается в логике, срабатывающей при записи набора:

  1. Процедуры модуля набора записей. В модуле самого регистра сведений могут быть определены обработчики событий ПередЗаписью или ПриЗаписи. Нередко в этих процедурах заложена логика автоматического восстановления движений или повторного считывания данных.
  2. Подписки на события. В конфигурации могут существовать объекты метаданных ПодпискаНаСобытие с источником РегистрСведенийНаборЗаписей.<ИмяРегистра>. Если в них вызывается общий модуль, который заново рассчитывает или перезаполняет строки, удаление фактически откатывается или перезаписывается новыми записями.

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


НЗ = РегистрыСведений.ПРОФИТ_Обеспечения.СоздатьНаборЗаписей();
НЗ.ОбменДанными.Загрузка = Истина;
НЗ.Отбор.Договор.Установить(СвязанныйДоговор);
НЗ.Записать();

Важно: использование ОбменДанными.Загрузка = Истина позволяет обойти сторонний код, однако необходимо убедиться, что обработчики в подписках действительно содержат стандартное условие Если ЭтотОбъект.ОбменДанными.Загрузка Тогда Возврат; КонецЕсли;.

Ограничения платформы при работе с набором записей

При настройке условий удаления важно учитывать архитектурные ограничения платформы 1С:

  1. Отбор только по измерениям. В объекте НаборЗаписей независимого регистра сведений допустимо накладывать отбор только по полям, являющимся измерениями (а также по полю Период, если регистр периодический). Наложить отбор по ресурсу или реквизиту на уровне набора невозможно.
  2. Ограничение на виды сравнения. В отборе набора записей поддерживается только прямое сопоставление (вид сравнения ВидСравнения.Равно или в определенных случаях ВидСравнения.ВСписке). Попытка применить сравнения вида Не равно, Больше или Содержит приведет к ошибке платформы.
  3. Несовпадение типов в составных измерениях. Если измерение имеет составной тип, пустая ссылка определенного справочника не эквивалентна значению Неопределено. Проверяйте соответствие типов передаваемых значений.

Другие факторы, маскирующие или отменяющие удаление

Если набор очищается, но результат не виден, проанализируем следующие ситуации:

  1. Откат внешней транзакции. Если удаление выполняется внутри транзакции (например, при проведении связанного документа или внутри блока НачатьТранзакцию()), любая последующая необработанная ошибка приведет к отмене всех действий. При наличии конструкции Попытка ... Исключение ошибка может быть скрыта, создавая ложное впечатление успешного выполнения.
  2. Ограничения прав на уровне записей (RLS). Если у пользователя отсутствуют права на удаление конкретных строк по критериям RLS, СУБД пропустит операцию. В служебных алгоритмах рекомендуется выполнять очистку с помощью вызова УстановитьПривилегированныйРежим(Истина).
  3. Кэширование динамических списков. В интерфейсе управляемого приложения данные в открытой форме списка регистра могут не обновиться мгновенно из-за кэширования платформы. Для принудительного обновления формы с клиента вызывается Элементы.Список.Обновить().
  4. Фоновые задания и механизмы синхронизации. Регламентные задания или модули интеграции могут моментально повторно создавать удаленные данные по внешним источникам.

Как надежно проверить результат удаления

Чтобы исключить влияние пользовательского интерфейса, проверим наличие записей прямым запросом к базе данных сразу после вызова метода Записать():


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

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

Если Результат.Пустой() Тогда
    Сообщить("Записи успешно удалены из информационной базы.");
Иначе
    Сообщить("Внимание: записи остались в базе!");
КонецЕсли;

Альтернативные способы удаления данных

В зависимости от задачи можно использовать и другие инструменты платформы:

  1. Менеджер записи (РегистрСведенийМенеджерЗаписи). Удобен для точечного удаления конкретной одной строки, когда известны значения абсолютно всех измерений первичного ключа:
    
    МЗ = РегистрыСведений.ПРОФИТ_Обеспечения.СоздатьМенеджерЗаписи();
    МЗ.Договор = СвязанныйДоговор;
    // Обязательно заполняются все остальные измерения ключа записи
    МЗ.Прочитать();
    Если МЗ.Выбран() Тогда
        МЗ.Удалить();
    КонецЕсли;
    
  2. Полная очистка регистра сведений. Если требуется очистить всю таблицу регистра без фильтрации, создается пустой набор записей вообще без отборов:
    
    НЗ = РегистрыСведений.ПРОФИТ_Обеспечения.СоздатьНаборЗаписей();
    НЗ.Записать(Истина);
    

Таким образом, для гарантированной очистки набора записей используем лаконичный вызов Отбор.Установить(), а при возникновении проблем в первую очередь проверяем процедуры модуля набора и активные подписки на события конфигурации.

← На главную