В практике разработки на платформе 1С:Предприятие часто возникает ситуация, когда бизнес-логика требует назначить один и тот же параметр (например, процент бонуса, скидку или цену) сразу нескольким контрагентам или товарам. На первый взгляд кажется логичным «сгруппировать» эти элементы в одной строке регистра, чтобы не плодить тысячи записей. Однако такое решение вступает в противоречие с архитектурой реляционных баз данных и механизмом индексации 1С. В этой статье мы подробно разберем, почему попытка впихнуть список в одно измерение — это плохая идея, и какие архитектурно верные альтернативы существуют.
Рассмотрим ситуацию: пользователю нужно установить бонус 5% для 10 контрагентов по 20 позициям номенклатуры. В классической структуре регистра сведений БонусыКонтрагентов (измерения: Контрагент, Номенклатура; ресурс: ПроцентБонуса) это потребует создания 200 записей. Пользователь видит огромный список и просит: «Сделайте так, чтобы я мог выбрать список контрагентов в одной строке».
Важно понимать: количество записей в базе данных не должно волновать конечного пользователя. Его волнует только удобство ввода данных. Программист же должен обеспечить производительность системы. Попытка удовлетворить просьбу «буквально» (через создание списка в измерении) приведет к невозможности быстрого поиска данных запросом.
Проанализируем ситуацию: если у группы контрагентов всегда одинаковые условия, значит, они образуют некую логическую общность. В типовых конфигурациях (ERP, УТ 11) для этого используется справочник Сегменты партнеров или Ценовые группы.
Рассмотрим шаги реализации этого метода:
СегментыКонтрагентов.Бонусы заменим измерение Контрагент на СегментКонтрагента.Теперь для 100 контрагентов одного сегмента в регистре будет храниться всего одна запись. Это идеальный способ «уменьшения количества записей» без потери производительности.
Если сегментация кажется избыточной, можно воспользоваться иерархией справочников. Рассмотрим этот вариант подробнее. Мы можем разрешить в измерении регистра выбирать не только элементы, но и группы (папки).
В этом случае при получении бонуса в запросе нам нужно будет проверять вхождение контрагента в группу. Однако стоит помнить, что прямая проверка В ИЕРАРХИИ в динамических списках или больших отчетах может замедлить работу. Тем не менее, это стандартный функционал платформы, который позволяет минимизировать количество ручного ввода.
Выясним, как сделать интерфейс удобным, сохранив правильную структуру данных. Вместо того чтобы заставлять пользователя работать напрямую с регистром, создадим документ УстановкаУсловийБонусов.
Разберем по шагам логику работы документа:
СписокКонтрагентов и СписокНоменклатуры.ПроцентБонуса.Посмотрим на пример кода в обработке проведения такого документа:
Процедура ОбработкаПроведения(Отказ, РежимПроведения)
НаборЗаписей = РегистрыСведений.БонусыКонтрагентов.СоздатьНаборЗаписей();
// Устанавливаем фильтр по регистратору, если регистр подчинен документу
НаборЗаписей.Отбор.Регистратор.Установить(Ссылка);
Для Каждого СтрКонтрагент Из СписокКонтрагентов Цикл
Для Каждого СтрНоменклатура Из СписокНоменклатуры Цикл
НоваяЗапись = НаборЗаписей.Добавить();
НоваяЗапись.Период = Дата;
НоваяЗапись.Контрагент = СтрКонтрагент.Контрагент;
НоваяЗапись.Номенклатура = СтрНоменклатура.Номенклатура;
НоваяЗапись.ПроцентБонуса = ПроцентБонуса;
КонецЦикла;
КонецЦикла;
НаборЗаписей.Записать();
КонецПроцедуры
Результат: пользователь видит одну компактную форму (как он и хотел), а система работает с индексированными данными, обеспечивая мгновенный поиск в запросах.
Проанализируем более гибкий вариант. Если условия бонусов зависят от множества факторов (регион, категория, объем закупок), использование ПВХ позволяет назначать свойства группам объектов. В регистре тогда хранятся связи не ссылок на объекты, а Значений свойств. Это делает систему максимально масштабируемой: вы добавляете нового контрагента в «Бонусную категорию А», и он автоматически подхватывает все настройки без редактирования регистра.
Иногда новички предлагают использовать ХранилищеЗначения или строку с перечисленными через запятую ID, чтобы хранить массив элементов в одной записи. Рассмотрим, почему это путь к катастрофе:
Контрагента1, системе придется прочитать все записи регистра, десериализовать их в память и программно искать вхождения. Если в регистре будет более 1000 записей, система начнет критически тормозить.В современных версиях платформы 1С (8.3.15+) можно программно группировать записи в списке регистра. Мы можем программно «схлопывать» одинаковые строки для визуального отображения пользователю. Это решается созданием динамического списка с произвольным запросом (GROUP BY), где в поле «Контрагент» выводится текст «Группа из N элементов». При этом физически в базе данных записи остаются разделенными, что сохраняет правильную архитектуру.
Подводя итог, можно сказать: никогда не идите на поводу у требований, нарушающих структуру базы данных. Если нужно хранить данные для нескольких элементов в одной логической привязке:
Помните, что «много записей» в регистре сведений — это не проблема, а штатный режим работы 1С, на который рассчитаны все механизмы индексации и поиска.