gifts2017

Главная и подчиненная таблицы в 1С - связывание

Опубликовал Александр Шкут (alex_shkut) в раздел Программирование - Практика программирования

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

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

Идея:

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

Реализация:

В поисках такой универсальной связки наткнулся на конструкцию вида:

Новый УникальныйИдентификатор;

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

ПриНачалеРедактирования - Табличного поля главной таблицы и Табличного поля подчиненной таблицы.

ПередУдалением - Табличного поля главной таблицы для очистки связанных строк подчиненной.

ПриАктивизацииСтроки - для отбора строк подчиненной таблицы.

Вот и все...

А теперь примеры обработчиков, кстати, они универсальны для любых решений.

 

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

Процедура ПодчиненнаяТаблицаПриНачалеРедактирования(Элемент, НоваяСтрока, Копирование)
	
	Данные = ЭлементыФормы.ГлавнаяТаблица.ТекущаяСтрока;
	ТекДанные = ЭлементыФормы.ПодчиненнаяТаблица.ТекущаяСтрока;
	Если НоваяСтрока Тогда
		ТекДанные.ИД = Данные.ИД;
	КонецЕсли;
	
КонецПроцедуры

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

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

И совсем небольшое дополнение - полю ИД устанавливаем Свойство:Индексировать = индексировать.

Поле Табличного Поля можно (и нужно во избежание) сделать недоступным для пользователя.

Жду ваших отзывов и критики :).

См. также

Подписаться Добавить вознаграждение

Комментарии

1. Котэ Пруидзе (kote) 17.05.13 01:50
Какую практическую задачу Вы решали, где Вам пришлось это применить?
2. Борис Моренко (BorisMor) 17.05.13 05:43
(1) kote, автор не открыл Америке. Иногда и правда требуется хранить "сложные данные" и первичный ключ (primary key) - это выход.
Но я предпочитаю использовать для связки осмысленный ключ (ссылку на справочник или значение).
Жаль что на уровне системы не реализована возможность делать ключ уникальным и обращаться по нему к данным из другой таблицы.
3. Александр Шкут (alex_shkut) 17.05.13 12:31
(1) Спасибо за признание решения. Просто в тех решениях, которые достались мне по наследству это связывание выполнялось по НомеруСтроки!!!. Представьте, что будет, если я отсортирую Главную таблицу?
Пример: ГлавнаяТаблица - поля (которые пашут и сеют - земля)
ПодчиненнаяТаблица - координаты этого Поля с GPS-Агромер.
Итак - к одному "полю" привязано до 500 координат ПО НОМЕРУ СТРОКИ. Нвадеюсь Вы меня поняли...
При использовании моего метода можно совсем забыть про синхронизацию.

Я использовал это решение в связке ВыполненнаяОперация - МногоИспользованыхРесурсов. Такая себе СводкаЗаПериод.
4. Александр Шкут (alex_shkut) 17.05.13 12:38
(2) Я выполнял поиск решения данной проблемы и не нашел однозначного решения, а мне оно было необходимо. Приведите мне, пожалуйста, хотя-бы пару ссылок с решением данного вопроса. Я вспомнил Access и искал аналогии в 1С. Поскольку я копал Access довольно подробно, а там он используется для синхронизации двух БД - UID был очевидным решением. В 1С на уровне движка можно организовать такое связывание генерируя UID для таблицы со Свойством:Главная и Подчиненная. Для решения многокаскадности достаточно два поля в каждой таблице - MUID SUID, и подчеркиваю только с установленным Свойством.
5. Борис Моренко (BorisMor) 18.05.13 17:25
(4) alex_shkut, думаю ссылки не нужны. Про примори кей знают все кто работал с базами. Сочувствую что ваш предшественник оказался таким "уником".
Когда говорил про связь на уровне движка то подразумевал связь между разными таблицами значений.
6. Сергей Кулешов (KulSer) 22.05.13 08:49
Я тоже делал аналогичное связывание по уникальному идентификатору, но, как теперь вижу, несколько перемудрил. Но Ваш код лаконичнее и с первого взгляда понятнее. Спасибо, Александр.
7. Sabfir Sabfir (Sabfir) 22.05.13 09:24
Если сначала добавить строку во вторую таблицу при отсутствии строки в первой таблице, то эти строки не свяжутся.
slawanix; +1 Ответить
8. Борис Скворцов (gaglo) 22.05.13 10:15
Так и не понял, почему тип УникальныйИдентификатор показался настолько выгодным. Раз поле для организации связки пришлось добавлять, почему не сделать его числовым? Конечно, не НомерСтроки, а какой-нибудь НомерДляСвязи, уникальный в пределах документа. Код обработчиков практически неизменен, только вместо одной строки "Новый УникальныйИдентификатор" пришлось бы написать пяток операторов, чтоб выяснить максимальный НомерДляСвязи да прибавить к нему 1. (Ну да, и еще УникальныйИдентификатор будет уникальным не только в пределах документа, а по всей базе и окрестностях...)
9. Екатерина Соколова (catena) 22.05.13 11:29
Вообще интересно, почему в таблице значений можно создать вложенную таблицу значений штатными средствами, а в табличных частях это не реализовано.
Maximysis; +1 Ответить
10. ash (ashvik) 22.05.13 12:20
Здесь еще нужно предусмотреть возможность копирования строки главной таблицы и, соответственно, копирование подчиненных строк с новым идентификатором.
11. Денис (Den_D) 22.05.13 14:14
Делал так еще в 2007 году, сейчас тоже так делаю, очень удобно. Как сказали в (10) не все ситуации рассмотрены в данном примере кода.
12. ффф ыыы (zqzq) 23.05.13 08:44
Конфигурация Управление небольшой фирмой - документ, например, ПриемНаРаботу - используются подчиненные таб. части. Функции для их поддержки в общем модуле УправлениеНебольшойФирмойКлиент. Так что да, автор изобрел велосипед.

Там, кстати, и такое обработано:

	Если ФормаДокумента.Элементы[ФормаДокумента.ИмяТабличнойЧасти].ТекущиеДанные = Неопределено Тогда
		Сообщение = Новый СообщениеПользователю;
		Сообщение.Текст = НСтр("ru = 'Не выбрана строка основной табличной части!'");
		Сообщение.Сообщить();


Для связи используется числовой инкрементный ключ КлючСвязи (число(5,0)) - занимает меньне иеста чем UUID (вроде бы), но ваше решение более устойчивое (если забыть, например, обработчик после удалеия, строки не переназначатся... хотя всё равно будут висеть невидимые и создавать косяки).
13. Александр Шкут (alex_shkut) 24.05.13 11:00
Спасибо за отзывы. Я не старался изобрести велосипед. Эта статья опубликована для тех, кто ищет решение и не находит. А примеры я привел здесь - в обсуждении. И причем это довольно известная компания :). А Уникальный идентификатор ценен тем, что он останется уникальным всегда и везде - как бы вы в последующем не разбрасывали информацию по базе - всегда можно отследить связи между данными.
Я постараюсь дописать базовый код так, чтобы он был минимально достаточным.
По поводу копирования подчиненных строк - это надо рассматривать в каждом конкретном случае, надо или нет. Код закомментированый для копирования я добавлю.
14. Александр Шкут (alex_shkut) 24.05.13 12:02
Если НоваяСтрока Тогда
		Элемент.ТекущаяСтрока.Сотрудник = ЭлементыФормы.РаботникиОрганизации.ТекущаяСтрока.Сотрудник;
	КонецЕсли;


Вот такое-вот решение при приеме на работу в моей конфигурации. Я специально не буду называть разработчика, т.к. это будет совсем неэтично. Мы здесь призваны улучшать то, что есть и создавать правильное новое.
В данном варианте УникальныйИдентификатор - это и есть Ссылка на Сотрудника.
15. Александр Шкут (alex_shkut) 10.02.14 15:56
Спасибо за голоса. Перечитал я все посты и понял. Я показал велосипед без колес :). Колеса поставит программист сам - какие ему нужно. Шоссейные (без копирования подчиненных) или горные (с ньюансами). Это достаточный минимум для тех, кто вообще не знает, как это сделать...
16. Вячеслав Павелко (slawanix) 12.02.16 17:59
Спасибо автору, плюсанул.
17. Игорь П (ehcore) 17.06.16 14:23
Спасибо автору, от себя хочу добавить код, переделанный под управляемые формы (также заблокировано добавление строки в подчиненную при пустой главной):
&НаКлиенте
Процедура ГлавнаяТаблицаПриНачалеРедактирования(Элемент, НоваяСтрока, Копирование)
	
	Данные = Элементы.ГлавнаяТаблица.ТекущиеДанные;
	Если НоваяСтрока Тогда 
	    Данные.ID = Новый УникальныйИдентификатор;
	КонецЕсли;
	
КонецПроцедуры

&НаКлиенте
Процедура ПодчиненнаяТаблицаПриНачалеРедактирования(Элемент, НоваяСтрока, Копирование)

	Данные = Элементы.ГлавнаяТаблица.ТекущиеДанные;
	
	ТекДанные = Элементы.ПодчиненнаяТаблица.ТекущиеДанные;
	Если НоваяСтрока Тогда
	    ТекДанные.ID = Данные.ID;
	КонецЕсли;
	
КонецПроцедуры

&НаКлиенте
Процедура ГлавнаяТаблицаПередУдалением(Элемент, Отказ)

	Данные = Элементы.ГлавнаяТаблица.ТекущиеДанные;
	Отбор = Новый Структура("ID",Данные.ID);
	Масс = Объект.ПодчиненнаяТаблица.НайтиСтроки(Отбор);
	Для каждого Строка из Масс Цикл
	    Объект.ПодчиненнаяТаблица.Удалить(Строка);
	КонецЦикла;
	
КонецПроцедуры

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

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


Ну и код модуля объекта(очищает подчиненную и присваивает новые ID строкам главной):
Процедура ПриКопировании(ОбъектКопирования)

	ПодчиненнаяТаблица.Очистить();
	Для Каждого Строка Из ГлавнаяТаблица Цикл
		Строка.ID = Новый УникальныйИдентификатор;
	КонецЦикла;	

КонецПроцедуры
...Показать Скрыть
Оберон; +1 Ответить
Для написания сообщения необходимо авторизоваться
Прикрепить файл
Дополнительные параметры ответа