Наверняка многие сталкивались с вопросом о связывании двух- и более таблиц на формах 1С по принципу главная-подчиненная. Один из возможных вариантов решения я приведу в этой статье. Некоторые решения я уже встречал, но они либо ограничивают возможности таблиц (невозможность сортировки, изменения номера строки и перестановки строк местами) либо требовали дополнительного кода по обработке различных изменений в связанной информации. Предлагаю более разумное и довольно простое решение.
Идея:
1. Необходима уникальная скрытая связка в двух таблицах, обеспечивающая простую в обработке синхронизацию полей главной и подчиненной таблиц.
Реализация:
В поисках такой универсальной связки наткнулся на конструкцию вида:
Новый УникальныйИдентификатор;
Как раз его и будем использовать для связывания. В обе табличные части документа добавляем поле с типом УникальныйИдентификатор. После этого необходимо в модуле формы обработать несколько событий, а именно:
ПриНачалеРедактирования — Табличного поля главной таблицы и Табличного поля подчиненной таблицы.
ПередУдалением — Табличного поля главной таблицы для очистки связанных строк подчиненной.
ПриАктивизацииСтроки — для отбора строк подчиненной таблицы.
Вот и все…
А теперь примеры обработчиков, кстати, они универсальны для любых решений.
Процедура ГлавнаяТаблицаПриНачалеРедактирования(Элемент, НоваяСтрока, Копирование)
Данные = ЭлементыФормы.ГлавнаяТаблица.ТекущаяСтрока;
Если НоваяСтрока Тогда
Данные.ИД = Новый УникальныйИдентификатор;
КонецЕсли;
КонецПроцедуры
Процедура ПодчиненнаяТаблицаПриНачалеРедактирования(Элемент, НоваяСтрока, Копирование)
Данные = ЭлементыФормы.ГлавнаяТаблица.ТекущаяСтрока;
ТекДанные = ЭлементыФормы.ПодчиненнаяТаблица.ТекущаяСтрока;
Если НоваяСтрока Тогда
ТекДанные.ИД = Данные.ИД;
КонецЕсли;
КонецПроцедуры
Процедура ГлавнаяТаблицаПередУдалением(Элемент, Отказ)
Данные = ЭлементыФормы.ГлавнаяТаблица.ТекущаяСтрока;
Отбор = Новый Структура("ИД",Данные.ИД);
Масс = ПодчиненнаяТаблица.НайтиСтроки(Отбор);
Для каждого Строка из Масс Цикл
ПодчиненнаяТаблица.Удалить(Строка);
КонецЦикла;
КонецПроцедуры
Процедура ГлавнаяТаблицаПриАктивизацииСтроки(Элемент)
Данные = ЭлементыФормы.ГлавнаяТаблица.ТекущаяСтрока;
Если Данные = Неопределено Тогда
Возврат;
КонецЕсли;
ЭлементыФормы.ПодчиненнаяТаблица.ОтборСтрок.ИД.Значение = Данные.ИД;
ЭлементыФормы.ПодчиненнаяТаблица.ОтборСтрок.ИД.Использование = истина;
КонецПроцедуры
И совсем небольшое дополнение — полю ИД устанавливаем Свойство:Индексировать = индексировать.
Поле Табличного Поля можно (и нужно во избежание) сделать недоступным для пользователя.
Жду ваших отзывов и критики :).




Какую практическую задачу Вы решали, где Вам пришлось это применить?
(1) kote, автор не открыл Америке. Иногда и правда требуется хранить «сложные данные» и первичный ключ (primary key) — это выход.
Но я предпочитаю использовать для связки осмысленный ключ (ссылку на справочник или значение).
Жаль что на уровне системы не реализована возможность делать ключ уникальным и обращаться по нему к данным из другой таблицы.
(1) Спасибо за признание решения. Просто в тех решениях, которые достались мне по наследству это связывание выполнялось по НомеруСтроки!!!. Представьте, что будет, если я отсортирую Главную таблицу?
Пример: ГлавнаяТаблица — поля (которые пашут и сеют — земля)
ПодчиненнаяТаблица — координаты этого Поля с GPS-Агромер.
Итак — к одному «полю» привязано до 500 координат ПО НОМЕРУ СТРОКИ. Нвадеюсь Вы меня поняли…
При использовании моего метода можно совсем забыть про синхронизацию.
Я использовал это решение в связке ВыполненнаяОперация — МногоИспользованыхРесурсов. Такая себе СводкаЗаПериод.
(2) Я выполнял поиск решения данной проблемы и не нашел однозначного решения, а мне оно было необходимо. Приведите мне, пожалуйста, хотя-бы пару ссылок с решением данного вопроса. Я вспомнил Access и искал аналогии в 1С. Поскольку я копал Access довольно подробно, а там он используется для синхронизации двух БД — UID был очевидным решением. В 1С на уровне движка можно организовать такое связывание генерируя UID для таблицы со Свойством:Главная и Подчиненная. Для решения многокаскадности достаточно два поля в каждой таблице — MUID SUID, и подчеркиваю только с установленным Свойством.
(4) думаю ссылки не нужны. Про примори кей знают все кто работал с базами. Сочувствую что ваш предшественник оказался таким «уником».
Когда говорил про связь на уровне движка то подразумевал связь между разными таблицами значений.
Я тоже делал аналогичное связывание по уникальному идентификатору, но, как теперь вижу, несколько перемудрил. Но Ваш код лаконичнее и с первого взгляда понятнее. Спасибо, Александр.
Если сначала добавить строку во вторую таблицу при отсутствии строки в первой таблице, то эти строки не свяжутся.
Так и не понял, почему тип УникальныйИдентификатор показался настолько выгодным. Раз поле для организации связки пришлось добавлять, почему не сделать его числовым? Конечно, не НомерСтроки, а какой-нибудь НомерДляСвязи, уникальный в пределах документа. Код обработчиков практически неизменен, только вместо одной строки «Новый УникальныйИдентификатор» пришлось бы написать пяток операторов, чтоб выяснить максимальный НомерДляСвязи да прибавить к нему 1. (Ну да, и еще УникальныйИдентификатор будет уникальным не только в пределах документа, а по всей базе и окрестностях…)
Вообще интересно, почему в таблице значений можно создать вложенную таблицу значений штатными средствами, а в табличных частях это не реализовано.
Здесь еще нужно предусмотреть возможность копирования строки главной таблицы и, соответственно, копирование подчиненных строк с новым идентификатором.
Делал так еще в 2007 году, сейчас тоже так делаю, очень удобно. Как сказали в (10) не все ситуации рассмотрены в данном примере кода.
Конфигурация Управление небольшой фирмой — документ, например, ПриемНаРаботу — используются подчиненные таб. части. Функции для их поддержки в общем модуле УправлениеНебольшойФирмойКлиент. Так что да, автор изобрел велосипед.
Там, кстати, и такое обработано:
Для связи используется числовой инкрементный ключ КлючСвязи (число(5,0)) — занимает меньне иеста чем UUID (вроде бы), но ваше решение более устойчивое (если забыть, например, обработчик после удалеия, строки не переназначатся… хотя всё равно будут висеть невидимые и создавать косяки).
Спасибо за отзывы. Я не старался изобрести велосипед. Эта статья опубликована для тех, кто ищет решение и не находит. А примеры я привел здесь — в обсуждении. И причем это довольно известная компания :). А Уникальный идентификатор ценен тем, что он останется уникальным всегда и везде — как бы вы в последующем не разбрасывали информацию по базе — всегда можно отследить связи между данными.
Я постараюсь дописать базовый код так, чтобы он был минимально достаточным.
По поводу копирования подчиненных строк — это надо рассматривать в каждом конкретном случае, надо или нет. Код закомментированый для копирования я добавлю.
Вот такое-вот решение при приеме на работу в моей конфигурации. Я специально не буду называть разработчика, т.к. это будет совсем неэтично. Мы здесь призваны улучшать то, что есть и создавать правильное новое.
В данном варианте УникальныйИдентификатор — это и есть Ссылка на Сотрудника.
Спасибо за голоса. Перечитал я все посты и понял. Я показал велосипед без колес :). Колеса поставит программист сам — какие ему нужно. Шоссейные (без копирования подчиненных) или горные (с ньюансами). Это достаточный минимум для тех, кто вообще не знает, как это сделать…
Спасибо автору, плюсанул.
Спасибо автору, от себя хочу добавить код, переделанный под управляемые формы (также заблокировано добавление строки в подчиненную при пустой главной):
Показать
Ну и код модуля объекта(очищает подчиненную и присваивает новые ID строкам главной):
Показать
(17), Спасибо, работает. Только нужно в процедуру
добавить одну строку:
потому что событие ПриАктивизацииСтроки по первой таблице срабатывает раньше, чем ПриНачалеРедактирования первой же таблице. В результате накладывается отбор в подчиненной таблице по пустому идентификатору.
Чем плохи УИДы.
Их нельзя передать в запрос внешней таблицей значений. Списком вроде можно. А вот в ТЗ — увы.
Спасибо! То что надо при моей задаче.