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

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

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

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

Вариант 1. Шаблон Master-Detail: связка двух табличных частей через КлючСвязи

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

Разберем реализацию этого варианта по шагам:

  1. Создание структуры данных документа. Добавим в документ первую табличную часть — Пробы с реквизитами Проба (тип СправочникСсылка.Пробы) и КлючСтроки (тип Число). Добавим вторую табличную часть — Показатели с реквизитами КлючСвязи (тип Число) и Показатель (тип СправочникСсылка.Показатели).
  2. Генерация уникального ключа при добавлении строки. В главной табличной части в событии ПриНачалеРедактирования или ПередНачаломДобавления назначаем уникальный номер строки для связки.
  3. Клиентская фильтрация подчиненной таблицы. На управляемой форме в событии ПриАктивизацииСтроки главной таблицы устанавливаем фильтр на подчиненную таблицу через платформенное свойство ОтборСтрок.

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


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

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


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

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

Вариант 2. Хранение в виде строки / JSON с интерактивным выбором в окне

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

Проанализируем алгоритм работы:

  1. В табличной части создаем строковый реквизит ПредставлениеПоказателей (для отображения на форме) и, при необходимости, реквизит ДанныеПоказателейJSON (тип Строка неограниченной длины).
  2. Для элемента формы в колонке показателей назначаем обработчик события НачалоВыбора и включаем свойство КнопкаВыбора.
  3. В обработчике вызываем встроенную форму выбора справочника с режимом множественного подбора или открываем стандартный диалог редактирования списка значений.

Посмотрим на пример открытия формы множественного выбора справочника:


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

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

На сервере полученный массив преобразуется в понятную для пользователя строку, а ссылки упаковываются в JSON через ЗаписатьJSON:


&НаСервере
Процедура СформироватьПредставлениеИСобратьJSON(ТекущаяСтрока, МассивСсылок)
    
    МассивПредставлений = Новый Массив;
    МассивИдентификаторов = Новый Массив;
    
    Для Каждого Ссылка Из МассивСсылок Цикл
        МассивПредставлений.Добавить(Строка(Ссылка));
        МассивИдентификаторов.Добавить(Строка(Ссылка.УникальныйИдентификатор()));
    КонецЦикла;
    
    ТекущаяСтрока.ПредставлениеПоказателей = СтрСоединить(МассивПредставлений, ", ");
    
    ЗаписьJSON = Новый ЗаписьJSON;
    ЗаписьJSON.УстановитьСтроку();
    ЗаписатьJSON(ЗаписьJSON, МассивИдентификаторов);
    ТекущаяСтрока.ДанныеПоказателейJSON = ЗаписьJSON.Закрыть();
    
КонецПроцедуры

Преимущество подхода: компактность интерфейса и наглядность для пользователя.

Ограничение: для выборки таких показателей в запросах проведения или регистрах потребуется программная десериализация JSON или дополнительная запись в регистры сведений.

Вариант 3. Использование дерева значений на форме

Если данные используются во внешней обработке или на форме отчета, оптимальным решением является использование элемента формы ТаблицаФормы с типом источника данных ДеревоЗначений. В этом случае первый уровень иерархии дерева занимает элемент «Проба», а дочерними строками выступают подчиненные «Показатели». При открытии формы дерево заполняется из плоских таблиц, а перед записью снова раскладывается в плоские строки табличной части.

Итоги

Для постоянного хранения в базе данных и проведения по регистрам оптимально использовать Шаблон Master-Detail с двумя табличными частями и связкой через ОтборСтрок. Это исключает избыточную нагрузку на сервер и сохраняет реляционную целостность базы данных. Если же задача носит сервисный или визуальный характер, можно использовать представление списков через множественный подбор и сериализацию данных в JSON.

← На главную