Как связать и скопировать данные из нескольких табличных частей в одну в документе 1С 8.3?

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

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

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

Вариант 1. Архитектурный подход: одна табличная часть в метаданных и разводка на форме

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

С точки зрения оптимизации базы данных и упрощения кода правильнее создать **одну табличную часть** Товары с реквизитами Товар и Цена. Если бизнес-требования требуют развести ввод товаров и цен по разным вкладкам или элементам интерфейса, реализуем это на уровне управляемой формы:

  1. В дереве метаданных документа оставляем одну табличную часть Товары с колонками Товар и Цена.
  2. На управляемую форму выносим эту табличную часть дважды (на разные страницы или панели).
  3. Для первой таблицы на форме оставляем видимой только колонку Товар.
  4. Для второй таблицы оставляем видимыми колонки Товар (для информации в режиме «только чтение») и Цена.

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

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

Если специфика бизнес-логики действительно требует наличия трех независимых табличных частей, наиболее надежным решением является применение ключей связи. Именно этот подход используется в типовых конфигурациях 1С (Управление торговлей, ERP, Комплексная автоматизация).

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

  1. В каждую из трех табличных частей документа (Товары, Цены, Итог) добавляем скрытый реквизит КлючСвязи с типом Строка (для сохранения GUID) или Число.
  2. При добавлении новой строки в первую табличную часть генерируем уникальный идентификатор и записываем его в КлючСвязи.
  3. Автоматически создаем парные строки во второй и третьей табличных частях, присваивая им тот же КлючСвязи.

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


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

&НаКлиенте
Процедура СинхронизироватьСтрокиПоКлючу(Знач КлючСвязи, Знач Номенклатура)
	
	// Синхронизация с ТЧ Цены
	Отбор = Новый Структура("КлючСвязи", КлючСвязи);
	НайденныеСтрокиЦены = Объект.Цены.НайтиСтроки(Отбор);
	
	Если НайденныеСтрокиЦены.Количество() = 0 Тогда
		СтрокаЦены = Объект.Цены.Добавить();
		СтрокаЦены.КлючСвязи = КлючСвязи;
	Иначе
		СтрокаЦены = НайденныеСтрокиЦены[0];
	КонецЕсли;
	
	// Синхронизация с ТЧ Итог
	НайденныеСтрокиИтог = Объект.Итог.НайтиСтроки(Отбор);
	Если НайденныеСтрокиИтог.Количество() = 0 Тогда
		СтрокаИтог = Объект.Итог.Добавить();
		СтрокаИтог.КлючСвязи = КлючСвязи;
	Иначе
		СтрокаИтог = НайденныеСтрокиИтог[0];
	КонецЕсли;
	
	// Заполняем реквизиты
	СтрокаИтог.Товар = Номенклатура;

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

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

Вариант 3. Пересчет и заполнение ТЧ «Итог» перед записью документа

Отслеживание всех действий пользователя на форме (перемещение строк кнопками «Вверх»/«Вниз», сортировка, интерактивное удаление) требует написания большого объема кода. Чтобы обезопасить себя от рассинхронизации данных, применим подход полной сборки итоговой таблицы в событии ПередЗаписью модуля объекта.

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


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

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

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


// Пример заполнения реквизитов одной строки из другой
ЗаполнитьЗначенияСвойств(СтрокаНазначения, СтрокаИсточника);

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

Мы рассмотрели различные пути решения задачи связывания табличных частей в 1С 8.3:

  1. **Оптимизация интерфейса** — наилучший выбор, если данные имеют связь 1 к 1. Достаточно одной табличной части в метаданных и разного отображения колонок на форме.
  2. **Ключи связи (GUID)** — стандартный выбор для гибкой синхронизации строк «на лету» в управляемой форме.
  3. **Сборка перед записью** — наиболее надежный способ предотвращения ошибок рассинхронизации данных при любых интерактивных действиях пользователя.
← На главную