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