Как программно удалить запись из регистра сведений в 1С: разбор методов и ошибок

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

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

Постановка задачи

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

Способ 1: Удаление через Менеджер записи

Этот метод подходит, когда нам нужно удалить одну конкретную строчку, и мы точно знаем значения всех её измерений (ключевых полей). Логика работы здесь похожа на поиск книги в библиотеке: чтобы найти и убрать конкретную книгу, нужно знать её точный шифр.

Рассмотрим алгоритм действий:

  1. Создаем менеджер записи.
  2. Заполняем только измерения (ключевые поля). Ресурсы и реквизиты заполнять нет смысла, так как они не участвуют в поиске уникальной записи.
  3. Считываем запись из базы.
  4. Если запись найдена — удаляем её.

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


// Неоптимальный подход с выборкой запросом
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ ... ИЗ РегистрСведений.МойРегистр ГДЕ Владелец = &Ссылка";
// ... выполнение запроса ...

Пока Выборка.Следующий() Цикл
    Запись = РегистрыСведений.МойРегистр.СоздатьМенеджерЗаписи();
    Запись.Владелец = Выборка.Владелец;
    // Лишнее действие: заполнение ресурсов не влияет на поиск
    Запись.Статус = Выборка.Статус; 
    
    Запись.Прочитать();
    Если Запись.Выбран() Тогда
        Запись.Удалить();
    КонецЕсли;
КонецЦикла;

Важные нюансы метода:

Способ 2: Удаление через Набор записей (Рекомендуемый)

Если ваша задача — удалить все записи по конкретному отбору (например, по Владельцу), использование МенеджерЗаписи внутри цикла является неэффективным и медленным. Гораздо правильнее использовать НаборЗаписей.

Логика здесь следующая: мы "говорим" платформе: "Возьми все записи с таким-то отбором и замени их на то, что я тебе дам". Если мы даем пустой набор, платформа удаляет старые записи.

Давайте разберем правильный код:


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

// Устанавливаем отбор. Это фильтр, по которому будут найдены удаляемые записи.
Набор.Отбор.Владелец.Установить(СсылкаНаДокумент);

// ВАЖНО: Мы не вызываем Прочитать(), если хотим просто удалить.
// Мы не вызываем Удалить(), так как у набора нет такого метода для базы данных.

// Мы записываем пустой набор. Параметр Истина означает "Замещать".
// Это значит: "Удали все, что соответствует отбору, и запиши то, что в наборе (пустоту)".
Набор.Записать(Истина);

Распространенные заблуждения при работе с набором:

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

Почему запись не удаляется? Диагностика проблем

Если вы написали верный код, но в режиме предприятия запись остается на месте, проанализируем возможные причины.

1. Неполный состав измерений (для Менеджера записи)

Как упоминалось выше, МенеджерЗаписи требует точного совпадения всех измерений. Проверьте структуру регистра. Возможно, там есть скрытые измерения (например, UUID строки или разделитель учета), которые вы не заполнили.

2. Откат транзакции

Если ваш код выполняется внутри большой транзакции (например, при проведении документа), и где-то позже происходит ошибка (Исключение или Отказ = Истина), то и удаление записи из регистра будет отменено. Проверьте журнал регистрации на наличие ошибок в момент выполнения кода.

3. Подписки на события и модули наборов

В типовых конфигурациях часто существуют подписки на события ПередЗаписью, которые могут:

Чтобы обойти проверки (действуйте осторожно!), можно использовать режим загрузки данных:


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

// Отключает вызов проверок и большинства обработчиков событий
Набор.ОбменДанными.Загрузка = Истина; 

Набор.Записать();

4. Ошибки прав доступа (RLS)

Если у пользователя настроено ограничение доступа на уровне записей (RLS), попытка удаления записи, к которой у него нет доступа на изменение, может пройти "тихо" (без ошибки), но фактически данные не изменятся. Это зависит от настройки режима БезопасныйРежим при выполнении кода. Убедитесь, что код выполняется в привилегированном модуле или у пользователя достаточно прав.

Выводы

Для гарантированного удаления записей лучше всего использовать Набор записей. Это атомарная операция, которая работает быстрее и понятнее для системы:

  1. Создаем набор.
  2. Устанавливаем отбор по ключевому измерению (например, Владельцу).
  3. Вызываем метод Записать().

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

← На главную