При разработке конфигураций на платформе 1С:Предприятие 8.3 программисты регулярно сталкиваются с необходимостью связать два независимых объекта. Классический пример — справочники Файлы и Папки. Ситуация усложняется, когда один и тот же файл должен находиться в нескольких папках одновременно (например, скан-копия общего договора относится и к папке контрагента, и к папке конкретного проекта). Это классическая связь вида «многие-ко-многим».
В этой статье мы подробно разберем, как правильно спроектировать структуру хранения таких данных в СУБД, почему использование табличных частей здесь неэффективно и как реализовать современный, интуитивно понятный пользовательский интерфейс с поддержкой механизма Drag-and-Drop на управляемых формах.
---
Прежде чем приступать к программированию интерфейса, определим наиболее надежный способ хранения связей. Рассмотрим два основных варианта:
Папки (или наоборот, в справочнике Файлы).Выясним причину, почему первый вариант (использование ТЧ) крайне нежелателен в реальных высоконагруженных системах:
Папки. Если несколько пользователей будут одновременно распределять файлы по одной и той же папке или редактировать другие её реквизиты, они неминуемо столкнутся с блокировками базы данных.Проанализируем ситуацию с использованием независимого регистра сведений. Создание регистра с измерениями Папка и Файл решает все эти проблемы:
Папка + Файл и Файл + Папка. Это гарантирует моментальное выполнение запросов в обе стороны.---
Рассмотрим подробнее процесс создания объектов в конфигураторе. Нам понадобятся три основных объекта:
Файлы — хранит информацию о файлах (имя, путь к файлу на сервере или двоичные данные).Папки — хранит информацию о папках (наименование, описание, владелец).СвязиПапокИФайлов (независимый, непериодический). В нем создаем два измерения:
Папка (тип: СправочникСсылка.Папки, свойство Ведущее включено).Файл (тип: СправочникСсылка.Файлы, свойство Ведущее включено).Включение свойства Ведущее для обоих измерений автоматически добавляет в стандартные формы справочников вкладку со списком связанных элементов, что значительно упрощает навигацию по умолчанию.
---
Посмотрим на пример построения удобной управляемой формы. Лучший вариант — спроектировать единую форму распределения файлов, которая разделена на три функциональные зоны:
Папки).Разберем по шагам, как настроить динамический список привязанных файлов. Нам потребуется передавать в него параметр текущей выделенной папки. Напишем запрос для этого списка:
ВЫБРАТЬ
СвязиПапокИФайлов.Файл КАК Файл,
СвязиПапокИФайлов.Файл.Наименование КАК Наименование
ИЗ
РегистрСведений.СвязиПапокИФайлов КАК СвязиПапокИФайлов
ГДЕ
СвязиПапокИФайлов.Папка = &ТекущаяПапка
Для того чтобы список привязанных файлов обновлялся автоматически при перемещении по списку папок, создадим обработчик события ПриАктивизацииСтроки у таблицы папок:
&НаКлиенте
Процедура СписокПапокПриАктивизацииСтроки(Элемент)
ТекущиеДанные = Элементы.СписокПапок.ТекущиеДанные;
Если ТекущиеДанные <> Неопределено Тогда
УстановитьОтборФайловНаСервере(ТекущиеДанные.Ссылка);
КонецЕсли;
КонецПроцедуры
&НаСервере
Процедура УстановитьОтборФайловНаСервере(ТекущаяПапка)
// Передаем значение текущей папки в параметры динамического списка
СписокФайловПапки.Параметры.УстановитьЗначениеПараметра("ТекущаяПапка", ТекущаяПапка);
КонецПроцедуры
---
Чтобы сделать интерфейс интерактивным, добавим возможность перетаскивать файлы из нижнего списка «Свободные файлы» прямо на нужную папку в левом списке или в верхнюю правую таблицу. Настроим свойства элементов формы:
СвободныеФайлы) установите свойство РазрешитьНачалоПеретаскивания в значение Истина.СписокПапок) установите свойство РазрешитьПеретаскивание в значение Истина.Теперь напишем обработчики событий для таблицы папок в модуле управляемой формы:
&НаКлиенте
Процедура СписокПапокПроверитьПеретаскивание(Элемент, ПараметрыПеретаскивания, СтандартнаяОбработка, Строка, Поле)
СтандартнаяОбработка = Ложь;
// Проверяем тип перетаскиваемых данных
Если ТипЗнч(ПараметрыПеретаскивания.Значение) = Тип("Массив") Тогда
Для Каждого ТекСсылка Из ПараметрыПеретаскивания.Значение Цикл
Если ТипЗнч(ТекСсылка) <> Тип("СправочникСсылка.Файлы") Тогда
ПараметрыПеретаскивания.Действие = ДействиеПеретаскивания.Отмена;
Возврат;
КонецЕсли;
КонецЦикла;
ПараметрыПеретаскивания.Действие = ДействиеПеретаскивания.Копирование;
ИначеЕсли ТипЗнч(ПараметрыПеретаскивания.Значение) = Тип("СправочникСсылка.Файлы") Тогда
ПараметрыПеретаскивания.Действие = ДействиеПеретаскивания.Копирование;
Иначе
ПараметрыПеретаскивания.Действие = ДействиеПеретаскивания.Отмена;
КонецЕсли;
КонецПроцедуры
&НаКлиенте
Процедура СписокПапокПеретаскивание(Элемент, ПараметрыПеретаскивания, СтандартнаяОбработка, Строка, Поле)
СтандартнаяОбработка = Ложь;
// "Строка" содержит идентификатор строки папки, на которую перетащили файлы
Если Не ЗначениеЗаполнено(Строка) Тогда
Возврат;
КонецЕсли;
ЦелеваяПапка = Элементы.СписокПапок.ДанныеСтроки(Строка).Ссылка;
// Собираем массив перетаскиваемых файлов
МассивФайлов = Новый Массив;
Если ТипЗнч(ПараметрыПеретаскивания.Значение) = Тип("Массив") Тогда
МассивФайлов = ПараметрыПеретаскивания.Значение;
Иначе
МассивФайлов.Добавить(ПараметрыПеретаскивания.Значение);
КонецЕсли;
// Вызываем серверную процедуру для записи связей в БД
ЗаписатьСвязиНаСервере(МассивФайлов, ЦелеваяПапка);
// Обновляем отображение динамических списков на клиенте
Элементы.СписокФайловПапки.Обновить();
КонецПроцедуры
&НаСервере
Процедура ЗаписатьСвязиНаСервере(МассивФайлов, ЦелеваяПапка)
Для Каждого СсылкаНаФайл Из МассивФайлов Цикл
// Используем менеджер записи для быстрого внесения информации
МенеджерЗаписи = РегистрыСведений.СвязиПапокИФайлов.СоздатьМенеджерЗаписи();
МенеджерЗаписи.Папка = ЦелеваяПапка;
МенеджерЗаписи.Файл = СсылкаНаФайл;
// Пытаемся прочитать запись, чтобы исключить дублирование данных
МенеджерЗаписи.Прочитать();
Если Не МенеджерЗаписи.Выбран() Тогда
МенеджерЗаписи.Папка = ЦелеваяПапка;
МенеджерЗаписи.Файл = СсылкаНаФайл;
МенеджерЗаписи.Записать(Истина);
КонецЕсли;
КонецЦикла;
КонецПроцедуры
---
В зависимости от требований бизнеса и используемой конфигурации, можно рассмотреть еще два интересных подхода к проектированию:
Файлы дополнительное сведение «Папки» с поддержкой множественного выбора значений. Всю логику записи связей в регистр сведений ДополнительныеСведения платформа возьмет на себя без написания дополнительного кода.Мы полностью разобрали варианты реализации сложной логики связывания файлов и папок. Выбор в пользу регистра сведений является наиболее гибким, масштабируемым и безопасным с точки зрения производительности решением.