Как правильно присвоить уникальный идентификатор строке табличной части в 1С?

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

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

Стандартный реквизит НомерСтроки для этой роли категорически не подходит. При удалении строк, изменении их порядка или ручной сортировке индексы сдвигаются. Это неизбежно приводит к рассинхронизации связанных данных — здесь пригодится обмен данными 1С через COM и веб-сервисы. В этой статье мы подробно разберем, как решить задачу присвоения строке действительно уникального и стабильного идентификатора, рассмотрим особенности хранения данных в СУБД, а также изучим лучшие практики и готовые стандарты 1С.

1. Как устроено хранение строк табличной части в СУБД

Прежде чем переходить к написанию кода, проанализируем, как платформа 1С:Предприятие работает с табличными частями на физическом уровне базы данных. Строка табличной части не является самостоятельным ссылочным объектом (в отличие от элементов справочников или документов).

В СУБД (MS SQL, PostgreSQL) для каждой табличной части создается отдельная физическая таблица — для этого подойдёт инструмент для анализа структуры таблиц СУБД. Первичным ключом (индексом) в ней выступает составное поле:

  1. Ссылка — уникальный идентификатор (GUID) родительского документа или элемента справочника.
  2. НомерСтроки — целочисленный индекс, определяющий порядок вывода строки на экран.

Когда пользователь меняет строки местами или удаляет строку из середины списка, платформа перезаписывает всю таблицу ТЧ для данного документа, обновляя поле НомерСтроки. Именно поэтому использовать номер строки для связи с внешними таблицами или другими ТЧ нельзя. Нам необходим выделенный реквизит, который будет хранить постоянный идентификатор на протяжении всей «жизни» строки.

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

Самый распространенный и надежный способ уникальной идентификации строки — использование глобального уникального идентификатора (GUID). Платформа 1С имеет встроенный тип данных УникальныйИдентификатор. Рассмотрим по шагам, как реализовать этот механизм.

Шаг 1. Настройка метаданных в Конфигураторе

Добавим в нужную табличную часть новый реквизит. Назовем его, например, ИдентификаторСтроки. При выборе типа данных крайне важно указать именно системный тип УникальныйИдентификатор, а не Строка(36).

Использование встроенного типа УникальныйИдентификатор имеет ключевые преимущества для производительности СУБД:

Шаг 2. Генерация идентификатора при добавлении новой строки

Выясним, в какой момент генерировать идентификатор. Лучше всего делать это интерактивно при добавлении строки пользователем на форме. Для этого разберем пример обработки события табличной части ПриНачалеРедактирования в модуле управляемой формы:


&НаКлиенте
Процедура ТоварыПриНачалеРедактирования(Элемент, НоваяСтрока, Копирование)
    
    Если НоваяСтрока Тогда
        // Если строка копируется, у нее уже может быть заполнен старый ID.
        // Нам нужно в любом случае гарантировать уникальность новой строки.
        ТекущиеДанные = Элементы.Товары.ТекущиеДанные;
        Если ТекущиеДанные <> Неопределено Тогда
            ТекущиеДанные.ИдентификаторСтроки = Новый УникальныйИдентификатор;
        КонецЕсли;
    КонецЕсли;
    
КонецПроцедуры

Шаг 3. Инициализация идентификаторов для существующих документов

Если в вашей базе данных уже есть заполненные документы, у существующих строк поле ИдентификаторСтроки окажется пустым. Нам потребуется разовая обработка, которая обойдет документы и заполнит пустые значения. Посмотрим на пример кода, который решает эту задачу на сервере:


&НаСервере
Процедура ЗаполнитьИдентификаторыСуществующихСтрок()
    
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ РАЗЛИЧНЫЕ
        |    РеализацияТоваровУслуг.Ссылка КАК Ссылка
        |ИЗ
        |    Документ.РеализацияТоваровУслуг.Товары КАК РеализацияТоваровУслугТовары
        |ГДЕ
        |    РеализацияТоваровУслугТовары.ИдентификаторСтроки = ЗНАЧЕНИЕ(УникальныйИдентификатор.ПустаяСсылка)";
        
    РезультатЗапроса = Запрос.Выполнить();
    Выборка = РезультатЗапроса.Выбрать();
    
    Пока Выборка.Следующий() Цикл
        ДокументОбъект = Выборка.Ссылка.ПолучитьОбъект();
        Для Каждого СтрокаТЧ Из ДокументОбъект.Товары Цикл
            Если Не ЗначениеЗаполнено(СтрокаТЧ.ИдентификаторСтроки) Тогда
                СтрокаТЧ.ИдентификаторСтроки = Новый УникальныйИдентификатор;
            КонецЕсли;
        КонецЦикла;
        
        // Отключаем проверки при записи, если это допустимо, для ускорения процесса
        ДокументОбъект.ОбменДанными.Загрузка = Истина;
        ДокументОбъект.Записать();
    КонецЦикла;
    
КонецПроцедуры

3. Альтернатива GUID — Ключ связи (числовой идентификатор)

Использование тяжелых 128-битных GUID оправдано не всегда. Если перед вами стоит локальная задача — например, связать на форме документа две табличные части (например, основную таблицу «Товары» и подчиненную таблицу «СерийныеНомера»), то использовать GUID избыточно — для этого подойдёт автоматизация связи строк и таблиц в 1С.

Для таких целей гораздо оптимальнее использовать простой числовой Ключ связи. Рассмотрим, как это реализовать:

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

Посмотрим на пример функции генерации числового ключа связи при добавлении новой строки в основную ТЧ:


&НаКлиенте
Процедура ТоварыПриНачалеРедактирования(Элемент, НоваяСтрока, Копирование)
    
    Если НоваяСтрока Тогда
        ТекущиеДанные = Элементы.Товары.ТекущиеДанные;
        Если ТекущиеДанные <> Неопределено Тогда
            ТекущиеДанные.КлючСвязи = ПолучитьМаксимальныйКлючСвязи() + 1;
        КонецЕсли;
    КонецЕсли;
    
КонецПроцедуры

&НаКлиенте
Функция ПолучитьМаксимальныйКлючСвязи()
    
    МаксКлюч = 0;
    Для Каждого СтрокаТЧ Из Объект.Товары Цикл
        Если СтрокаТЧ.КлючСвязи > МаксКлюч Тогда
            МаксКлюч = СтрокаТЧ.КлючСвязи;
        КонецЕсли;
    КонецЦикла;
    Возврат МаксКлюч;
    
КонецФункции

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

4. Использование подчиненных справочников

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

Рассмотрим плюсы и минусы такого подхода:

Поэтому к использованию справочников стоит прибегать только тогда, когда строка ТЧ превращается в самостоятельную бизнес-сущность, требующую ведения собственной истории или дополнительных реквизитов.

5. Стандарты БСП и типовых конфигураций (ERP, КА, УТ)

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

  1. ИдентификаторСтроки — тип УникальныйИдентификатор.
  2. КодСтроки — тип Число.

В типовых решениях также встроены готовые программные механизмы. Например, программное заполнение уникальных идентификаторов строк при формировании документов кодом выполняется вызовом экспортных методов из общего модуля:


// Пример использования готового общего модуля из ERP/УТ
ОбщегоНазначенияУТ.ДобавитьИдентификаторСтрокВТаблицу(Объект.Товары);

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

6. Временные идентификаторы платформы в управляемых формах

Рассмотрим частую ошибку начинающих разработчиков. Платформа 1С в управляемом интерфейсе предоставляет механизм получения идентификатора строки через коллекцию ДанныеФормыКоллекция.

Метод Элементы.ИмяТаблицы.ТекущаяСтрока возвращает числовой идентификатор. Его также можно получить с помощью метода ПолучитьИдентификатор() на клиенте. Однако помните о важном ограничении:

Этот идентификатор живет только в рамках текущего сеанса работы формы!

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

7. Получение GUID в запросах (платформа 8.3.22+)

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

Теперь в языке запросов доступна встроенная функция УникальныйИдентификатор(). Выглядит это следующим образом:


ВЫБРАТЬ
    РеализацияТоваровУслугТовары.Ссылка КАК ДокументСсылка,
    УникальныйИдентификатор(РеализацияТоваровУслугТовары.ИдентификаторСтроки) КАК СтрокаGUID
ИЗ
    Документ.РеализацияТоваровУслуг.Товары КАК РеализацияТоваровУслугТовары

Это нововведение значительно упрощает построение интеграционных пакетов данных, позволяя формировать готовые текстовые GUID прямо на уровне СУБД в один шаг — поможет универсальная выгрузка документов в XML и JSON.

Резюме

Мы детально разобрали варианты уникальной идентификации строк табличной части в 1С. Подведем итоги:

← На главную