Как исправить ошибку «Индекс находится за границами массива» при удалении строк в связанных табличных частях 1С

Программист 1С v8.3 (Управляемые формы)
← На главную

В процессе разработки сложных документов в среде 1С:Предприятие 8.3 часто возникает необходимость реализовать каскадное удаление данных. Например, когда при удалении строки из основной табличной части должны автоматически удаляться связанные записи в других (подчиненных) таблицах. Начинающие разработчики часто сталкиваются с ошибкой «Индекс находится за границами массива» при выполнении таких операций. В этой статье мы подробно разберем, почему возникает эта ошибка, проанализируем типичный пример кода и разработаем надежный алгоритм работы с коллекциями строк.

Разбор проблемной ситуации

Рассмотрим сценарий, описанный пользователем: на форме документа есть три табличные части: Нарушения (основная), ПриостановленныеРаботы (подчиненная) и ФайлыПоНарушениям (подчиненная). Связь между ними осуществляется по уникальному полю ИдентификаторНарушения. Разработчик попытался реализовать удаление в обработчике события ПередУдалением основной таблицы.

Проанализируем исходный программный код, в котором возникает ошибка:


&НаКлиенте
Процедура НарушенияПередУдалением(Элемент, Отказ)
    
    Если Элементы.Нарушения.ТекущаяСтрока = Неопределено Тогда
        Возврат;
    КонецЕсли;
    
    Идентификатор = Элементы.Нарушения.ТекущиеДанные.ИдентификаторНарушения;
    
    // Блок 1: Удаление из таблицы ПриостановленныеРаботы
    ПодчиненныеСтроки = Объект.ПриостановленныеРаботы.НайтиСтроки(Новый Структура("ИдентификаторНарушения", Идентификатор));
    Для Каждого ПодчиненнаяСтрока Из ПодчиненныеСтроки Цикл
        Объект.ПриостановленныеРаботы.Удалить(ПодчиненнаяСтрока);
    КонецЦикла;
    
    // Блок 2: Удаление из таблицы ФайлыПоНарушениям (Здесь возникает ошибка)
    ПодчиненныеСтрокиФайловНарушений = Объект.ФайлыПоНарушениям.НайтиСтроки(Новый Структура("ИдентификаторНарушения", Идентификатор));
    Для Каждого ПодчиненнаяСтрока Из ПодчиненныеСтрокиФайловНарушений Цикл
        Объект.ПриостановленныеРаботы.Удалить(ПодчиненнаяСтрока);
    КонецЦикла;

КонецПроцедуры

Выясняем причину ошибки

Причиной аварийного завершения программы в данном случае является классическая ошибка «copy-paste» (копирования-вставки). Давайте посмотрим внимательно на второй цикл удаления. Программа ищет строки в таблице Объект.ФайлыПоНарушениям, но пытается удалить их из таблицы Объект.ПриостановленныеРаботы.

Почему же 1С выдает именно ошибку «Индекс находится за границами массива»? Выясним логику работы платформы:

  1. Метод НайтиСтроки() возвращает массив объектов типа ДанныеФормыЭлементКоллекции. Эти объекты жестко привязаны к своей родительской коллекции (табличной части).
  2. Метод Удалить() может принимать на вход либо индекс строки, либо саму строку (объект).
  3. Когда мы передаем методу Объект.ПриостановленныеРаботы.Удалить() строку, которая физически принадлежит таблице ФайлыПоНарушениям, платформа пытается определить индекс этой строки внутри коллекции ПриостановленныеРаботы.
  4. Так как строки там нет, внутренние механизмы поиска индекса возвращают некорректное значение или вызывают исключение при попытке обращения к памяти, что и интерпретируется как выход индекса за границы массива.

Правильное решение проблемы

Для исправления конкретно этой ошибки необходимо привести в соответствие коллекцию, в которой ведется поиск, и коллекцию, из которой производится удаление. Рассмотрим исправленный вариант кода:


// Правильное удаление во втором блоке
ПодчиненныеСтрокиФайловНарушений = Объект.ФайлыПоНарушениям.НайтиСтроки(Новый Структура("ИдентификаторНарушения", Идентификатор));
Для Каждого ПодчиненнаяСтрока Из ПодчиненныеСтрокиФайловНарушений Цикл
    // Важно: Удаляем именно из той ТЧ, в которой искали!
    Объект.ФайлыПоНарушениям.Удалить(ПодчиненнаяСтрока);
КонецЦикла;

Важные нюансы удаления строк в цикле

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

1. Смещение индексов. Если бы мы удаляли строки не через массив, найденный методом НайтиСтроки, а простым циклом по счетчику (Для Сч = 0 По ТЧ.Количество() - 1), то после удаления первой же строки (индекс 0) вторая строка заняла бы её место и получила индекс 0. Цикл же перешел бы к индексу 1, пропустив таким образом одну строку. Поэтому при удалении по индексу всегда следует использовать обратный порядок перебора:


ВсегоСтрок = Объект.ПриостановленныеРаботы.Количество();
Для Сч = 1 По ВсегоСтрок Цикл
    Индекс = ВсегоСтрок - Сч;
    Строка = Объект.ПриостановленныеРаботы[Индекс];
    Если Строка.ИдентификаторНарушения = Идентификатор Тогда
        Объект.ПриостановленныеРаботы.Удалить(Индекс);
    КонецЕсли;
КонецЦикла;

2. Использование директивы &НаСервере. Выполнение операций удаления в циклах на клиенте (&НаКлиенте) — не самая лучшая практика. Каждое удаление строки может инициировать пересчет визуальных элементов формы, итогов и других связанных данных, что замедляет работу интерфейса. Проанализируем более профессиональный подход: передачу управления на сервер.


&НаСервере
Процедура УдалитьСвязанныеСтрокиНаСервере(Идентификатор)
    
    ПараметрыОтбора = Новый Структура("ИдентификаторНарушения", Идентификатор);
    
    // Массив строк для удаления
    Массив1 = Объект.ПриостановленныеРаботы.НайтиСтроки(ПараметрыОтбора);
    Для Каждого Стр Из Массив1 Цикл
        Объект.ПриостановленныеРаботы.Удалить(Стр);
    КонецЦикла;
    
    Массив2 = Объект.ФайлыПоНарушениям.НайтиСтроки(ПараметрыОтбора);
    Для Каждого Стр Из Массив2 Цикл
        Объект.ФайлыПоНарушениям.Удалить(Стр);
    КонецЦикла;
    
КонецПроцедуры

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

Итоговые рекомендации

Чтобы ваш код был качественным и не вызывал ошибок «Индекс за границами массива», следуйте этим правилам:

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

← На главную