В практике разработки на платформе 1С:Предприятие часто возникают задачи, где необходимо совместить хранение одиночных (уникальных) данных и списочных (множественных) данных в рамках одного объекта. Типичный пример — задача с собеседования: создать регистр для телефонов сотрудников, где личный номер может быть только один, а номеров родственников — неограниченное количество. При этом проверку должна выполнять сама платформа за счет своей архитектуры, а не только программный код.
В этой статье мы подробно разберем несколько подходов к проектированию такой системы, проанализируем механику работы индексов регистра сведений и выясним, какое решение является наиболее элегантным с точки зрения архитектора 1С.
Прежде чем переходить к решениям, проанализируем, как 1С обеспечивает уникальность записей. Уникальность записи в регистре сведений определяется набором его измерений. Платформа создает в СУБД первичный ключ (Primary Key), состоящий из всех измерений регистра. Если мы пытаемся записать строку с комбинацией измерений, которая уже существует, система выдаст ошибку «Запись с такими ключевыми полями существует».
Основная сложность задачи заключается в том, что для «личного телефона» нам нужна уникальность по полю Сотрудник, а для «телефонов родственников» — уникальность по комбинации Сотрудник + Кто-тоЕще. Рассмотрим, как этого добиться.
Это решение считается наиболее правильным в контексте «задач на сообразительность». Мы используем тот факт, что измерение может быть пустым.
Спроектируем структуру следующим образом:
Сотрудник (Тип: СправочникСсылка.Сотрудники).Родственник (Тип: СправочникСсылка.ФизическиеЛица или Строка). Данное поле оставляем незаполненным для личного номера.НомерТелефона (Тип: Строка).Разберем, как это работает на практике:
Важный нюанс: Чтобы различать типы записей в интерфейсе, можно использовать условное оформление: если поле Родственник не заполнено, выводить в колонке текст «Личный».
Рассмотрим ситуацию, когда нам нужно хранить просто «дополнительные телефоны» без привязки к конкретным личностям родственников. В этом случае можно использовать числовое измерение.
Структура регистра:
Сотрудник.НомерПП (Тип: Число).НомерТелефона.Логика работы:
Условимся, что НомерПП = 0 всегда зарезервирован за личным телефоном. Все остальные номера (родственников или дополнительные) записываются с инкрементом: 1, 2, 3 и так далее. Платформа автоматически ограничит количество записей с индексом 0 одной строкой на сотрудника, выполняя требование задачи.
Хотя задача часто подразумевает «архитектурное» решение, в реальных проектах чаще используется программная проверка. Это позволяет сделать систему более гибкой и выводить пользователю понятные сообщения об ошибках.
Проанализируем пример кода, который необходимо разместить в модуле регистра сведений в обработчике ПередЗаписью:
Процедура ПередЗаписью(Отказ, Замещение)
// Если запись идет через ОбменДанными.Загрузка, обычно проверки отключают
Если ОбменДанными.Загрузка Тогда
Возврат;
КонецЕсли;
// Допустим, у нас есть ресурс ВидТелефона (Перечисление: Личный, Родственника)
// Проверяем только если в текущем наборе есть "Личный"
КоличествоЛичных = 0;
Для Каждого Запись Из ЭтотОбъект Цикл
Если Запись.ВидТелефона = Перечисления.ВидыТелефонов.Личный Тогда
КоличествоЛичных = КоличествоЛичных + 1;
КонецЕсли;
КонецЦикла;
Если КоличествоЛичных > 1 Тогда
Сообщить("У сотрудника не может быть более одного личного телефона!");
Отказ = Истина;
Возврат;
КонецЕсли;
// Также нужно проверить базу данных, если мы записываем не весь набор сразу,
// а по одной записи (хотя для РС это редкость при стандартных формах)
// ... здесь должен быть запрос к таблице регистра ...
КонецПроцедуры
Преимущество этого метода в том, что мы не перегружаем структуру регистра лишними измерениями ради логики контроля. Помните: каждое новое измерение увеличивает размер индексов и может замедлять запись в высоконагруженных системах.
Если мы проектируем крупную систему, стоит задаться вопросом: являются ли личный телефон и телефон родственника одной и той же сущностью? Личный телефон — это зачастую обязательный атрибут самого сотрудника.
Рассмотрим альтернативный вариант:
Сотрудники. Это на 100% гарантирует уникальность «один сотрудник — один телефон» на уровне структуры справочника.Сотрудник, а вторым измерением — Родственник или НомерТелефона.Такой подход делает структуру данных прозрачной: нам не нужно гадать, какая запись в регистре является главной, так как основной контакт всегда находится «под рукой» в карточке сотрудника.
Выясним, какой метод выбрать в зависимости от ситуации:
Подводя итог, можно сказать, что гибкость платформы 1С позволяет решить задачу уникальности множеством способов. Выбор конкретного метода зависит от того, насколько критична производительность и насколько «чистой» должна быть архитектура вашего решения.