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