Как сослаться на запись регистра сведений в 1С: проектируем архитектуру без ошибок

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

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

Что делать, если в другом объекте (например, в измерении другого регистра сведений) вам крайне необходимо указать конкретную запись из первого регистра? В этой статье мы подробно разберем, почему стандартный РегистрСведенийКлючЗаписи не подходит для хранения в базе данных, почему попытка сериализовать ключ в строку — это опасный антипаттерн, и рассмотрим три надежных архитектурных решения, проверенных на практике и в типовых конфигурациях фирмы «1С».

Рассмотрим ситуацию по шагам и проанализируем, как решить эту задачу правильно.

В чем суть проблемы и почему «КлючЗаписи» нельзя сохранить в базе данных?

В платформе 1С существует тип данных РегистрСведенийКлючЗаписи.<ИмяРегистра>. Однако этот объект спроектирован исключительно для работы в оперативной памяти встроенного языка. Он создается динамически для решения интерфейсных или программных задач:

  1. Для передачи ссылки на конкретную запись в параметры формы (чтобы открыть форму записи).
  2. Для установки блокировок в транзакциях.
  3. Для получения навигационных ссылок в интерфейсе.

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

Почему сериализация ключа в строку — это грубый антипаттерн?

У разработчиков часто возникает соблазн обойти ограничения платформы «хитрым» путем: взять все измерения записи регистра сведений, упаковать их в структуру, сериализовать эту структуру в JSON, XML или во внутреннюю строку с помощью ЗначениеВСтрокуВнутр(), а затем сохранить полученную длинную строку в текстовое измерение другого регистра.

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

  1. Катастрофическая потеря производительности СУБД. Индексация длинных строковых полей в СУБД (MS SQL, PostgreSQL) работает крайне неэффективно. При росте объема данных поиск и запись в такой регистр начнут вызывать жесткие блокировки и замедлять всю систему.
  2. Невозможность использования в запросах. Если вам понадобится связать две таблицы (сделать ЛЕВОЕ СОЕДИНЕНИЕ) по такому «сериализованному ключу», вам придется производить строковые операции прямо в запросе. В 1С это приведет к тому, что СУБД не сможет использовать индексы (произойдет Index Scan вместо Index Seek), и тяжелый запрос просто «уронит» производительность базы.
  3. Нарушение ссылочной целостности. Представьте, что одним из измерений первого регистра был справочник Контрагенты. Вы сериализовали ключ в строку, где записался GUID этого контрагента. Если пользователь удалит этого контрагента или заменит его, ваша сериализованная строка во втором регистре превратится в скрытую «битую ссылку». Платформа при «Тестировании и исправлении» не сможет обнаружить эту связь и очистить данные, что приведет к логической замусоренности базы данных.

Посмотрим на правильные, надежные архитектурные паттерны решения этой задачи.

Решение №1: Паттерн «Ключи аналитики» (Стандарт 1С:ERP, КА, УТ)

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

Алгоритм реализации паттерна:

1. Создадим справочник (например, Справочник.КлючиАналитикиУчетаНоменклатуры).

2. В этом справочнике создадим реквизиты, которые полностью дублируют набор измерений вашего регистра сведений (например: Номенклатура, Характеристика, Склад).

3. В целевых регистрах вместо хранения кучи отдельных измерений или попыток записать строку мы создаем всего одно измерение с типом СправочникСсылка.КлючиАналитикиУчетаНоменклатуры.

4. При записи данных в систему мы сначала ищем в справочнике элемент с нужной комбинацией реквизитов. Если такого элемента нет — программно создаем его, а затем записываем полученную ссылку справочника в наш регистр.

Разберем пример кода для поиска или создания ключа аналитики:


Функция ПолучитьКлючАналитики(Номенклатура, Характеристика, Склад) Экспорт
    
    // Пытаемся найти существующий ключ аналитики
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |   Ключи.Ссылка КАК Ссылка
        |ИЗ
        |   Справочник.КлючиАналитикиУчетаНоменклатуры КАК Ключи
        |ГДЕ
        |   Ключи.Номенклатура = &Номенклатура
        |   И Ключи.Характеристика = &Характеристика
        |   И Ключи.Склад = &Склад";
        
    Запрос.УстановитьПараметр("Номенклатура", Номенклатура);
    Запрос.УстановитьПараметр("Характеристика", Характеристика);
    Запрос.УстановитьПараметр("Склад", Склад);
    
    РезультатЗапроса = Запрос.Выполнить();
    Если Не РезультатЗапроса.Пустой() Тогда
        Выборка = РезультатЗапроса.Выбрать();
        Выборка.Следующий();
        Возврат Выборка.Ссылка;
    КонецЕсли;
    
    // Если не найден — создаем новый элемент справочника
    НовыйКлюч = Справочники.КлючиАналитикиУчетаНоменклатуры.СоздатьЭлемент();
    НовыйКлюч.Номенклатура = Номенклатура;
    НовыйКлюч.Характеристика = Характеристика;
    НовыйКлюч.Склад = Склад;
    НовыйКлюч.Наименование = Строка(Номенклатура) + " / " + Строка(Характеристика);
    
    Попытка
        НовыйКлюч.Записать();
        Возврат НовыйКлюч.Ссылка;
    Исключение
        ВызватьИсключение "Не удалось записать ключ аналитики: " + ОписаниеОшибки();
    КонецПопытки;
    
КонецФункции

Преимущества: База данных работает максимально быстро. Связи в запросах происходят по одному простому полю-ссылке (GUID справочника), сохраняется строгая ссылочная целостность, а размер таблиц СУБД существенно уменьшается.

Решение №2: Простая денормализация (Дублирование измерений)

Если количество измерений в первом регистре невелико (например, 2 или 3 простых измерения), а связываемых таблиц в вашей системе немного, самым простым и эффективным решением будет дублирование этих измерений во втором регистре сведений.

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

Проанализируем пример запроса для связи двух регистров по нескольким измерениям:


ВЫБРАТЬ
    Цены.Номенклатура КАК Номенклатура,
    Цены.ТипЦен КАК ТипЦен,
    Цены.Цена КАК Цена,
    Скидки.ПроцентСкидки КАК ПроцентСкидки
ИЗ
    РегистрСведений.ЦеныНоменклатуры.СрезПоследних(&Период, ) КАК Цены
    ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.СкидкиНоменклатуры КАК Скидки
        ПО Цены.Номенклатура = Скидки.Номенклатура
        И Цены.ТипЦен = Скидки.ТипЦен

Преимущества: Максимальная простота реализации, отсутствие необходимости создавать лишние метаданные (справочники-ключи) и идеальная производительность за счет правильного использования индексов СУБД, которые платформа 1С автоматически строит по измерениям регистров.

Решение №3: Изменение концепции метаданных (Перевод регистра в Справочник)

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

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

Как исправить эту ошибку:

Вместо регистра сведений создайте Справочник. Каждая «запись» станет элементом этого справочника, у которого автоматически появится полноценное поле Ссылка. Ее вы сможете без каких-либо ограничений использовать в измерениях, ресурсах и реквизитах любых других объектов конфигурации. А периодичность (если она была нужна в регистре) можно реализовать либо табличной частью, либо подчиненным регистром сведений, где измерением будет ссылка на ваш новый справочник.

Полезный лайфхак: Использование навигационных ссылок для интерфейса

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

Для таких интерактивных задач идеально подходят Навигационные ссылки 1С. Платформа умеет кодировать ключ записи регистра сведений в уникальную строку формата URL.

Рассмотрим, как получить и использовать такую ссылку в коде:


// 1. Получаем ключ записи конкретной строки регистра
ОтборЗаписи = Новый Структура("Номенклатура, ТипЦен", ВыбранныйТовар, ВыбранныйТипЦен);
КлючЗаписи = РегистрыСведений.ЦеныНоменклатуры.СоздатьКлючЗаписи(ОтборЗаписи);

// 2. Формируем уникальную навигационную ссылку (строку)
СсылкаДляИнтерфейса = ПолучитьНавигационнуюСсылку(КлючЗаписи);
// Результат будет выглядеть примерно так: "e1cib/data/РегистрСведений.ЦеныНоменклатуры?Номенклатура=..."

// 3. Эту строчку можно безопасно сохранить в текстовый реквизит.
// При необходимости открыть форму пользователю, выполняем:
ПерейтиПоНавигационнойСсылке(СсылкаДляИнтерфейса);

Важное предупреждение: Использовать навигационные ссылки можно только для интерактивных действий пользователя (открытие форм, клики в отчетах). Использовать их для связи таблиц в алгоритмах проведения документов или в запросах категорически запрещено по причинам производительности, описанным выше.

Подведем итоги

При работе с регистрами сведений в 1С всегда помните об ограничениях необъектных сущностей. Избегайте «костылей» в виде сериализации данных в строки. Вместо этого используйте проверенные архитектурные решения:

← На главную