Как организовать хранение и отображение нескольких значений в одной ячейке табличной части 1С

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

В процессе разработки конфигураций на платформе 1С часто возникает задача, когда одной строке табличной части (ТЧ) должно соответствовать несколько значений ссылочного типа. Например, в документе «Заказ покупателя» для одной номенклатурной позиции может потребоваться указать список примененных скидок, несколько ответственных мастеров или набор дополнительных характеристик. Стандартная структура табличной части предполагает, что в одной ячейке хранится только одно значение. Разберем детально, как обойти это ограничение и реализовать полноценную связь «один ко многим» внутри одного объекта.

Способ 1. Использование подчиненной табличной части и ключа связи

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

Шаг 1. Подготовка структуры данных

Проанализируем необходимые изменения в метаданных объекта (документа или справочника):

  1. В основной табличной части (например, Товары) создадим реквизит КлючСвязи. В качестве типа данных лучше использовать Строка с длиной 36 символов. Хотя 1С поддерживает тип УникальныйИдентификатор, использование строки более универсально, так как строку проще использовать в запросах в качестве параметра.
  2. Создадим вторую табличную часть (например, ДополнительныеЗначения). В ней добавим два реквизита: КлючСвязи (тип Строка, 36) и Значение (тип нужного вам справочника или документа).

Шаг 2. Программная связь на форме

Теперь выясним, как обеспечить отображение данных. На форму документа выведем основную таблицу Товары. Для отображения связанных значений можно использовать либо отдельную таблицу на форме, которая будет фильтроваться при активации строки, либо динамически формируемый список в самой ячейке.

Рассмотрим пример кода для фильтрации подчиненной таблицы при смене строки в основной таблице:


Процедура ТоварыПриАктивизацииСтроки(Элемент)
    ТекущиеДанные = Элементы.Товары.ТекущиеДанные;
    Если ТекущиеДанные = Неопределено Тогда
        Элементы.ДополнительныеЗначения.ОтборСтрок = Неопределено;
    Иначе
        // Устанавливаем фильтр для подчиненной ТЧ по ключу связи
        Отбор = Новый Структура("КлючСвязи", ТекущиеДанные.КлючСвязи);
        Элементы.ДополнительныеЗначения.ОтборСтрок = Новый ФиксированнаяСтруктура(Отбор);
    КонецЕсли;
КонецПроцедуры

Способ 2. Визуальное объединение значений в одной колонке

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

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

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


Функция ОбновитьПредставление(ТекущийКлюч)
    Текст = "";
    НайденныеСтроки = ДополнительныеЗначения.НайтиСтроки(Новый Структура("КлючСвязи", ТекущийКлюч));
    Для Каждого СтрокаЗн Из НайденныеСтроки Цикл
        Текст = Текст + Строка(СтрокаЗн.Значение) + "; ";
    КонецЦикла;
    Возврат Текст;
КонецФункции

Важные технические нюансы реализации

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

1. Копирование строк

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


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

2. Удаление строк

При удалении строки из основной таблицы «мусорные» записи в подчиненной ТЧ автоматически не удаляются. Рекомендуется очищать их в событии ПередУдалением или непосредственно перед записью объекта в базу данных, выполняя проверку на наличие «сиротских» записей (записей с ключами, которых нет в основной таблице).

3. Использование GUID

Как упоминалось в обсуждении, использование типа УникальныйИдентификатор напрямую в реквизитах ТЧ может вызвать трудности при написании запросов. Рекомендуется преобразовывать его в строку Строка(Новый УникальныйИдентификатор()). Это обеспечит стопроцентную уникальность и простоту при отладке.

Способ 3. Сериализация в JSON (Альтернативный подход)

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

Посмотрим на пример логики сохранения массива ссылок в строку:


// Сохранение (например, перед записью или после выбора в списке)
МассивСсылок = Новый Массив;
МассивСсылок.Добавить(Справочники.Номенклатура.НайтиПоНаименованию("Товар 1"));
МассивСсылок.Добавить(Справочники.Номенклатура.НайтиПоНаименованию("Товар 2"));

ЗаписьJSON = Новый ЗаписьJSON;
ЗаписьJSON.УстановитьСтроку();
ЗаписатьJSON(ЗаписьJSON, МассивСсылок);
СтрокаДляХранения = ЗаписьJSON.Закрыть();

// Чтение
ЧтениеJSON = Новый ЧтениеJSON;
ЧтениеJSON.УстановитьСтроку(СтрокаДляХранения);
МассивСсылок = ПрочитатьJSON(ЧтениеJSON);

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

Резюме

Выбор метода зависит от ваших бизнес-целей:

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

← На главную