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