Как сохранить и вывести порядок записей в регистре сведений 1С?

Программист 1С v8.3 (Управляемые формы) 1C:Бухгалтерия IT и автоматизация бизнеса
← На главную

Разработчики в среде «1С:Предприятие 8» часто сталкиваются со следующей проблемой: пользователи заполняют список членов комиссии в документе в определенном порядке (например, сначала председатель, затем ключевые члены комиссии, потом остальные), эти данные записываются в независимый регистр сведений, но при выводе на печать или открытии формы список оказывается полностью перемешанным. Попытки упорядочить данные программно по ссылочному полю или наименованию приводят лишь к алфавитной сортировке, что не решает задачу сохранения пользовательского порядка ввода.

В этой статье мы подробно разберем, почему СУБД и платформа 1С ведут себя подобным образом, как устроено физическое хранение данных в регистрах сведений и какими методами можно гарантировать вывод строк в том порядке, в котором их ввел пользователь, даже если конфигурация находится на поддержке.

Почему СУБД «перемешивает» записи в регистре сведений?

Для начала проанализируем базовые принципы работы реляционных баз данных (таких как MS SQL Server, PostgreSQL или IBM DB2). В реляционной теории таблицы представляют собой неупорядоченные множества. Это означает, что без явного указания инструкции ORDER BY (в языке запросов 1С — УПОРЯДОЧИТЬ ПО) СУБД имеет право вернуть строки в абсолютно любом порядке.

Когда мы пишем запрос без сортировки, СУБД обычно выдает строки в порядке их физического расположения на диске или в порядке сканирования индексов. Для независимого непериодического регистра сведений платформа 1С автоматически создает в базе данных уникальный кластерный индекс. Этот индекс строится по всем измерениям регистра в той последовательности, в которой они расположены в дереве метаданных конфигуратора.

Представим структуру регистра из нашего примера:

Кластерный индекс для такой таблицы на уровне СУБД будет состоять из полей: Объект + ЧленКомиссии + Должность + Роль. СУБД физически сортирует и хранит строки таблицы на диске именно в соответствии с этим индексом. Когда мы выбираем данные по конкретному объекту (документу), СУБД делает выборку и возвращает строки, отсортированные по следующему по порядку полю индекса — ЧленКомиссии.

Особенности сортировки по ссылочным полям (UUID)

Многие начинающие разработчики полагают, что сортировка по полю типа СправочникСсылка (в нашем случае ЧленКомиссии) должна происходить по наименованию (ФИО физического лица). Однако это не так. На уровне базы данных любая ссылка представляет собой 16-байтовое бинарное число — уникальный идентификатор (UUID или GUID).

Когда СУБД сортирует записи по измерению ЧленКомиссии, она сравнивает именно эти шестнадцатеричные уникальные идентификаторы. Так как UUID генерируются платформой случайным образом (или последовательно, но без привязки к алфавиту), визуально для пользователя этот порядок кажется абсолютно хаотичным. Именно поэтому физическое лицо Власова может оказаться в списке выше Антоновой — просто шестнадцатеричный код UUID Власовой оказался математически меньше, чем у Антоновой.

Вывод очевиден: полагаться на естественный порядок записей в регистре сведений нельзя. Для сохранения пользовательской последовательности строк нам требуется явное числовое поле порядка.

Как решить проблему порядка строк: пошаговые варианты

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

Вариант 1. Добавление числового измерения «НомерСтроки» (Порядок)

Если у вас есть возможность вносить изменения в структуру метаданных основной конфигурации, это самый простой и надежный способ.

  1. Добавьте в регистр сведений новое измерение с именем НомерСтроки (или Порядок).
  2. Установите для него тип Число, длина 3, неотрицательное.
  3. При записи набора записей из формы документа программно заполняйте это поле последовательными числами (1, 2, 3 и т.д.) в зависимости от индекса строки в табличной части формы.
  4. В запросе печатной формы обязательно укажите сортировку по этому полю:

ВЫБРАТЬ
    СоставыКомиссий.ЧленКомиссии КАК ЧленКомиссии,
    СоставыКомиссий.Должность КАК Должность,
    СоставыКомиссий.Роль КАК Роль
ИЗ
    РегистрСведений.АХДКОСоставыКомиссийДокументов КАК СоставыКомиссий
ГДЕ
    СоставыКомиссий.Объект В(&МассивОбъектов)
УПОРЯДОЧИТЬ ПО
    СоставыКомиссий.НомерСтроки

Вариант 2. Создание регистра-сателлита в расширении конфигурации

Что делать, если конфигурация находится на строгой поддержке, а изменения вносить запрещено? Начиная с платформы 1С 8.3, мы можем использовать расширения конфигурации. Однако напрямую добавить новое измерение в заимствованный регистр сведений в расширении нельзя. В этом случае мы можем применить паттерн «Регистр-сателлит».

Разберем этот алгоритм подробно:

  1. В расширении конфигурации создайте новый независимый регистр сведений с именем Расш_ПорядокСоставаКомиссии.
  2. Создайте в нем измерения:
    • Объект (тип заимствован из основной конфигурации, например, ДокументСсылка.АктСписания)
    • ЧленКомиссии (тип СправочникСсылка.ФизическиеЛица)
  3. Создайте ресурс:
    • НомерСтроки (тип Число)
  4. В расширении перехватите модуль формы редактирования состава комиссии или событие записи основного регистра сведений. При записи данных в основной регистр параллельно делайте запись в ваш регистр-сателлит, фиксируя индекс строки для каждой связки документа и члена комиссии.
  5. В запросе печатной формы свяжите два регистра левым соединением и выполните упорядочивание:

ВЫБРАТЬ
    АХДКОСоставыКомиссий.ЧленКомиссии КАК ЧленКомиссии,
    АХДКОСоставыКомиссий.Должность КАК Должность,
    АХДКОСоставыКомиссий.Роль КАК Роль
ИЗ
    РегистрСведений.АХДКОСоставыКомиссийДокументов КАК АХДКОСоставыКомиссий
    ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.Расш_ПорядокСоставаКомиссии КАК Расш_Порядок
        ПО АХДКОСоставыКомиссий.Объект = Расш_Порядок.Объект
        И АХДКОСоставыКомиссий.ЧленКомиссии = Расш_Порядок.ЧленКомиссии
ГДЕ
    АХДКОСоставыКомиссий.Объект В(&МассивОбъектов)
УПОРЯДОЧИТЬ ПО
    ЕСТЬNULL(Расш_Порядок.НомерСтроки, 999)

Вариант 3. Хранение порядка во временном строковом реквизите (JSON-сериализация)

Если создание дополнительного регистра кажется вам избыточным, можно воспользоваться программным методом сохранения последовательности UUID в текстовом поле документа.

  1. Через расширение добавьте к документу реквизит Расш_ПорядокЧленовКомиссии с типом Строка (неограниченной длины).
  2. При интерактивном сохранении состава комиссии в форме документа соберите упорядоченный массив уникальных идентификаторов членов комиссии, сериализуйте его в JSON и запишите в созданный реквизит:

// Код выполняется на сервере при сохранении данных формы
МассивGUID = Новый Массив;
Для Каждого СтрокаКомиссии Из ТаблицаКомиссииНаФорме Цикл
    МассивGUID.Добавить(Строка(СтрокаКомиссии.ЧленКомиссии.УникальныйИдентификатор()));
КонецЦикла;

ЗаписьJSON = Новый ЗаписьJSON;
ЗаписьJSON.УстановитьСтроку();
ЗаписатьJSON(ЗаписьJSON, МассивGUID);
ОбъектДокумента.Расш_ПорядокЧленовКомиссии = ЗаписьJSON.Закрыть();
  1. При формировании печатной формы сначала получите этот JSON-массив, десериализуйте его обратно в список значений или массив, а затем программно отсортируйте полученную из основного регистра таблицу значений по индексу соответствия UUID.

Вариант 4. Перенос данных в табличную часть документа

Проанализируем архитектуру решения. Использование независимого регистра сведений для хранения состава комиссии конкретного документа часто является избыточным и проектируется лишь для того, чтобы «не снимать документ с поддержки». Если у вас есть возможность использовать расширения конфигурации, гораздо более правильным архитектурным решением будет полный отказ от использования внешнего регистра сведений для хранения строчной части документа.

Выполните следующие шаги:

  1. Через расширение добавьте непосредственно в документ новую табличную часть с именем Расш_СоставКомиссии.
  2. Добавьте в нее реквизиты: ЧленКомиссии, Должность, Роль.
  3. При выводе на форму используйте стандартную табличную часть. Платформа 1С автоматически создает для табличных частей системное поле НомерСтроки на уровне базы данных и гарантирует, что порядок строк, заданный пользователем кнопками «Переместить вверх» / «Переместить вниз», всегда сохранится без написания дополнительного кода.
  4. Перепишите запрос печатной формы для получения данных напрямую из табличной части документа:

ВЫБРАТЬ
    СоставКомиссии.ЧленКомиссии КАК ЧленКомиссии,
    СоставКомиссии.Должность КАК Должность,
    СоставКомиссии.Роль КАК Роль
ИЗ
    Документ.АктСписания.Расш_СоставКомиссии КАК СоставКомиссии
ГДЕ
    СоставКомиссии.Ссылка В(&МассивОбъектов)
УПОРЯДОЧИТЬ ПО
    СоставКомиссии.НомерСтроки

Данный подход не только решает проблему с порядком строк раз и навсегда, но и существенно ускоряет работу системы, избавляя СУБД от лишних соединений таблиц, а также упрощает транзакционную целостность данных при записи документа.

← На главную