В процессе разработки конфигураций на платформе 1С:Предприятие 8 начинающие специалисты часто сталкиваются с задачей синхронизации данных между различными бизнес-сущностями. Классический пример: у нас есть справочник Военнослужащие и справочник УчебнаяДеятельностьКурсантов. В обоих объектах конфигурации предусмотрены одинаковые поля: Фамилия, Имя, Отчество, Группа, Звание и Должность. Перед нами встает задача: сделать так, чтобы при выборе конкретного курсанта все сопутствующие данные заполнялись в его карточке учебной деятельности автоматически.
В этой статье мы подробно разберем, почему физическое дублирование реквизитов в базе данных является серьезной ошибкой проектирования, как быстро решить задачу "в лоб" с помощью программного кода, и как перестроить структуру данных по лучшим стандартам разработки 1С.
Прежде чем перейти к написанию программного кода, проанализируем структуру базы данных. Если мы создаем физические поля «Фамилия», «Имя», «Звание» в обоих справочниках, мы нарушаем одно из фундаментальных правил реляционных баз данных — третью нормальную форму (3NF). Данные начинают дублироваться.
Чем это грозит на практике?
Военнослужащие, в ранее созданных элементах справочника УчебнаяДеятельностьКурсантов останется старое звание. Данные перестанут быть актуальными.Рассмотрим правильные и компромиссные варианты реализации этой задачи.
Самое простое и архитектурно верное решение в рамках управляемых форм — это отказ от дублирования реквизитов на уровне метаданных и использование ссылочного типа. Выясним, как это реализовать на практике.
Разберем процесс настройки по шагам:
УчебнаяДеятельностьКурсанта удаляем все дублирующие реквизиты (Фамилия, Имя, Отчество, Звание, Должность).Военнослужащий с типом ссылки СправочникСсылка.Военнослужащие.УчебнаяДеятельностьКурсанта.Объект, раскрываем его по «плюсику» и находим добавленный реквизит Военнослужащий.Военнослужащий еще раз по «плюсику». Перед нами открываются все его личные реквизиты (Фамилия, Имя, Звание и т.д.).Военнослужащий.Звание) левой кнопкой мыши в левое окно элементов формы.Платформа 1С автоматически создаст на форме элементы поле ввода, связав их свойством «ПутьКДанным» по цепочке: Объект.Военнослужащий.Звание. При этом данные реквизиты будут доступны только для чтения, что исключит опечатки пользователей, гарантирует всегда актуальные сведения на форме и спасет базу данных от дублирования информации.
Важное предупреждение о производительности: Использование обращений "через точку" в путях к данным на управляемой форме очень удобно, но имеет скрытый подводный камень. Каждый раз при отрисовке формы система будет выполнять неявные запросы (операции LEFT JOIN) к таблице СУБД Военнослужащие. На высоконагруженных системах с десятками тысяч записей это может привести к замедлению открытия карточек. Если критически важна скорость работы, лучше использовать динамическое считывание данных при открытии формы в одну транзакцию.
Бывают ситуации (легаси-код или жесткие требования бизнеса), когда данные скопировать необходимо. Например, если нам нужно зафиксировать звание и должность курсанта именно в момент совершения учебного действия, чтобы эти исторические данные не перезаписывались в будущем при продвижении курсанта по службе. В этом случае физическое копирование данных оправданно.
Выясним, как правильно написать код автозаполнения, избегая рутинного присвоения каждого поля вручную.
В платформе 1С для этих целей существует мощный встроенный инструмент — процедура ЗаполнитьЗначенияСвойств(). Она автоматически сопоставляет имена реквизитов источника и приемника и переносит значения только по совпадающим идентификаторам полей.
Рассмотрим пример правильного кода, написанного в модуле управляемой формы справочника УчебнаяДеятельностьКурсанта:
&НаКлиенте
Процедура ВоеннослужащийПриИзменении(Элемент)
// Передаем управление на сервер для безопасной работы с базой данных
ЗаполнитьРеквизитыНаСервере();
КонецПроцедуры
&НаСервере
Процедура ЗаполнитьРеквизитыНаСервере()
Если ЗначениеЗаполнено(Объект.Военнослужащий) Тогда
// Автоматически копируем Фамилию, Имя, Отчество, Группу, Звание, Должность
ЗаполнитьЗначенияСвойств(Объект, Объект.Военнослужащий);
Иначе
// Очищаем реквизиты формы, если пользователь стер значение в поле "Военнослужащий"
Объект.Фамилия = "";
Объект.Имя = "";
Объект.Отчество = "";
Объект.Группа = "";
Объект.Звание = "";
Объект.Должность = "";
КонецЕсли;
КонецПроцедуры
Этот код отрабатывает мгновенно, гарантирует заполнение всех одноименных полей и корректно обрабатывает ситуацию, когда пользователь передумал и очистил ведущее поле ввода на форме.
Если учебная деятельность курсанта всегда жестко привязана к самому курсанту, отличным архитектурным решением будет использование стандартного платформенного механизма подчинения справочников.
Для этого выполним следующие действия:
УчебнаяДеятельностьКурсанта.Военнослужащие.В результате этих действий в справочнике учебной деятельности автоматически появится стандартный реквизит Владелец. Это дает мощные преимущества:
При настройке связи справочников начинающие разработчики часто сталкиваются с ошибкой платформы при попытке записи элемента: «Поле "Наименование" не заполнено!». Это происходит потому, что разработчик пытается переопределить стандартное поле наименования на форме под нужды вывода ФИО военнослужащего, меняя его свойство «ПутьКДанным».
Посмотрим на два изящных варианта решения этой проблемы:
Вариант А (Если текстовое наименование не нужно в учете):
В конфигураторе перейдите в свойства справочника УчебнаяДеятельностьКурсанта на вкладку «Данные» и установите параметр «Длина наименования» в значение 0. Платформа перестанет требовать заполнение этого поля, а представление элемента в интерфейсе программы будет формироваться автоматически по ссылке на владельца или ключевой реквизит.
Вариант Б (Автоматическое формирование наименования при записи):
Если вам все же нужно информативное наименование для списков и отчетов, скройте поле ввода наименования с формы элемента и перенесите логику его заполнения в программный модуль. Откройте Модуль объекта справочника УчебнаяДеятельностьКурсанта и пропишите обработчик события:
Процедура ПередЗаписью(Отказ)
// Предотвращаем запись пустого или некорректного наименования
Если ЗначениеЗаполнено(Военнослужащий) Тогда
Наименование = Строка(Военнослужащий) + " - Учебная деятельность";
Иначе
Наименование = "Новая запись учебной деятельности";
EndIf;
КонецПроцедуры
Теперь программа самостоятельно сформирует красивое и понятное наименование карточки при каждой записи элемента, избавляя пользователя от рутины.
Проанализируем природу данных. Учебная деятельность курсанта (оценки, посещаемость, прохождение зачетов) — это не классический справочник сущностей, а поток событий, распределенных во времени. Использование справочников для хранения таких записей в 1С является устаревшей методикой (Legacy).
Правильный подход — создание Регистра сведений:
УчебнаяДеятельностьКурсантов.Курсант (тип данных: СправочникСсылка.Военнослужащие).Звание, Должность, Оценка, Группа.Такой подход позволит вам использовать мощный встроенный механизм платформы — метод СрезПоследних(). С его помощью вы легко в любой момент времени сможете получить срез актуальных данных по курсанту (в какой группе он состоял, какое звание носил на определенный день года), что при использовании обычных справочников потребовало бы написания сложных и неоптимальных запросов.