Как реализовать неизменную нумерацию строк в табличной части при удалении

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

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

В рамках этой статьи мы подробно разберем, почему штатный механизм ведет себя именно так, и проанализируем несколько эффективных способов создания "неизменного" номера. Мы рассмотрим как простые варианты с добавлением реквизитов, так и продвинутые методы, используемые в типовых конфигурациях уровня ERP и Бухгалтерия предприятия 3.0.

Метод 1. Создание пользовательского реквизита «КодСтроки»

Разберем самый надежный и часто используемый метод — добавление собственного числового реквизита в табличную часть. Назовем его, например, ФиксНомер или КодСтроки. При реализации работы с идентификаторами строк важно обеспечить их уникальность в рамках документа.

Пошаговая реализация:

  1. В дереве метаданных найдем нужный документ и его табличную часть. Чтобы быстро выполнить просмотр реквизитов объекта метаданных, можно использовать специализированные консоли. Добавим новый реквизит табличной части с именем ИдентификаторСтроки и типом Число (длина 10, точность 0).
  2. Выведем этот реквизит на форму документа, а стандартное поле НомерСтроки скроем. В некоторых случаях удобно использовать редактор форм в режиме предприятия, чтобы оперативно подправить свойства элементов без изменения конфигурации.
  3. Нам необходимо обеспечить автоматическое заполнение этого поля при добавлении новой строки. Проанализируем ситуацию: нам нужно найти максимальное уже существующее значение в этой колонке и прибавить к нему единицу.

Для реализации логики заполнения в модуле формы документа в обработчике события ПриОкончанииРедактирования (или ПередЗаписью) напишем следующий код:


&НаСервере
Процедура ЗаполнитьИдентификаторСтрокиНаСервере(ТекущаяСтрока)
    
    // Если идентификатор уже присвоен, ничего не делаем
    Если ТекущаяСтрока.ИдентификаторСтроки <> 0 Тогда
        Возврат;
    КонецЕсли;
    
    МаксНомер = 0;
    // Обходим коллекцию строк для поиска максимального значения
    Для Каждого СтрокаТЧ Из Объект.Товары Цикл
        Если СтрокаТЧ.ИдентификаторСтроки > МаксНомер Тогда
            МаксНомер = СтрокаТЧ.ИдентификаторСтроки;
        КонецЕсли;
    КонецЦикла;
    
    ТекущаяСтрока.ИдентификаторСтроки = МаксНомер + 1;
    
КонецПроцедуры

Таким образом, при удалении строки с номером "5" из списка, где было 10 строк, номера остальных (1, 2, 3, 4, 6, 7, 8, 9, 10) останутся неизменными. Новая добавленная строка получит номер 11.

Метод 2. Использование механизма «Ключ связи» (опыт типовых конфигураций)

Проанализируем, как аналогичная задача решена в типовых решениях, таких как БП 3.0 или ERP 2.5. Там часто используется механизм ключа связи в сложных табличных частях. Это особенно полезно, если строки основной табличной части (например, Товары) связаны со строками другой табличной части (например, Спецификации).

В таких случаях используется общая процедура для генерации ключей. Мы можем позаимствовать эту логику. Вместо ручного перебора строк в цикле, можно использовать возможности платформы по работе с таблицами значений. Если вам требуется выполнить создание кода новой таблицы значений из реквизита на форме, можно воспользоваться готовой обработкой для ускорения кодинга. Рассмотрим пример заполнения ключей перед записью документа в модуле объекта:


Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
    
    // Используем стандартный подход: пересчет ключей только для пустых значений
    МаксимальныйКлюч = 0;
    Для Каждого СтрокаТЧ Из Товары Цикл
        МаксимальныйКлюч = Макс(МаксимальныйКлюч, СтрокаТЧ.КлючСвязи);
    КонецЦикла;
    
    Для Каждого СтрокаТЧ Из Товары Цикл
        Если СтрокаТЧ.КлючСвязи = 0 Тогда
            МаксимальныйКлюч = МаксимальныйКлюч + 1;
            СтрокаТЧ.КлючСвязи = МаксимальныйКлюч;
        КонецЕсли;
    КонецЦикла;
    
КонецПроцедуры

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

Важный нюанс: Копирование строк

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

Чтобы этого избежать, разберем порядок действий в модуле формы. Нам нужно перехватить событие ПриКопировании для таблицы:


&НаКлиенте
Процедура ТоварыПриКопировании(Элемент, ОбъектКопирования)
    // Очищаем скопированный идентификатор, чтобы система присвоила новый
    Элемент.ТекущиеДанные.ИдентификаторСтроки = 0;
    // Вызываем процедуру присвоения нового номера
    ЗаполнитьИдентификаторСтрокиНаСервере(Элемент.ТекущиеДанные);
КонецПроцедуры

Важно: Всегда обнуляйте ключевые поля при копировании, иначе логика неизменности номеров нарушится из-за дублей.

Метод 3. «Мягкое удаление» строк

Рассмотрим альтернативный подход, который предложили опытные участники сообщества. Вместо физического удаления строки из коллекции ДанныеФормыКоллекция, мы можем использовать механизм пометки на удаление внутри таблицы.

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

  1. Добавим в ТЧ реквизит Удалена (Тип: Булево).
  2. В интерфейсе заменим стандартную кнопку удаления на свою команду.
  3. При нажатии на эту команду будем устанавливать Строка.Удалена = Истина.
  4. С помощью Условного оформления настроим скрытие таких строк или их визуальное зачеркивание.

Этот способ идеален, если заказчик требует строгого соблюдения последовательности номеров без "дырок". Строка физически остается в базе под своим номером, но не участвует в расчетах и не видна пользователю (если настроить отбор в элементе формы "Таблица").

Метод 4. Использование Идентификатора строки (GUID)

Если ваша задача — обеспечить связь строки с внешними системами или проанализировать граф зависимостей ссылок реквизитов табличных частей, использование уникальных идентификаторов является наиболее надежным решением. Вместо числа можно использовать УникальныйИдентификатор.

Хотя пользователю неудобно смотреть на строку вида 550e8400-e29b-41d4-a716-446655440000, этот метод является самым надежным в многопользовательской среде. Вы можете хранить GUID в скрытом реквизите, а пользователю показывать красивый порядковый номер, вычисляемый на лету, либо хранить оба значения.

Подведение итогов

Мы рассмотрели несколько подходов к решению задачи. Выбор конкретного метода зависит от целей:

Помните, что штатное поле НомерСтроки — это лишь проекция индекса строки в памяти, и пытаться "заставить" его не меняться программно — тупиковый путь. Создание собственного реквизита является единственно верным архитектурным решением в данной ситуации.

← На главную