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