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

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

В процессе разработки на платформе «1С:Предприятие 8» часто возникает задача организации отложенной обработки данных. Если с документами или справочниками все предельно просто — мы можем легко сохранить ссылку на объект (ДокументСсылка или СправочникСсылка) в очередь задач, то с регистрами сведений (РС) и накопления (РН) ситуация обстоит сложнее. Объект типа «Набор записей» не имеет уникального идентификатора (UUID) в базе данных, так как является динамической коллекцией, определяемой параметрами отбора.

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

Разбор ситуации: в чем сложность идентификации набора записей?

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

Способ идентификации набора напрямую зависит от режима записи регистра:

  1. Подчиненные регистры (РН и подчиненные РС): Здесь все просто. Однозначным идентификатором набора записей выступает регистратор. Достаточно сохранить ссылку на документ-регистратор (ДокументСсылка), чтобы в дальнейшем прочитать по нему весь набор записей.
  2. Независимые регистры сведений (РС): В данном случае однозначным идентификатором набора является совокупность ключевых полей (измерений регистра и периода для периодических регистров). Именно структуру этого отбора нам и необходимо сохранить для последующей обработки.

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

Решение 1. Сериализация структуры отбора в один реквизит (Хранилище значения или JSON)

Рассмотрим простейший вариант, предложенный автором темы: упаковка всех полей отбора в структуру с последующим сохранением в один реквизит нашей очереди задач (например, в регистр сведений «ОчередьЗадач» с типом ресурса ХранилищеЗначения или неограниченная строка).

Разберем по шагам, как это реализовать с помощью сериализации структуры в JSON. Использование JSON предпочтительнее стандартного ХранилищаЗначения, так как строку JSON легче читать при отладке, она весит меньше и быстрее обрабатывается СУБД.

Посмотрим на пример кода, выполняемый в обработчике события ПередЗаписью или ПриЗаписи набора записей регистра сведений:


// Определяем структуру отбора независимого регистра
СтруктураОтбора = Новый Структура;
Для Каждого ЭлементОтбора Из ЭтотОбъект.Отбор Цикл
    Если ЭлементОтбора.Использование Тогда
        СтруктураОтбора.Вставить(ЭлементОтбора.Имя, ЭлементОтбора.Значение);
    КонецЕсли;
КонецЦикла;

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

// Сериализуем структуру в строку JSON
ЗаписьJSON = Новый ЗаписьJSON;
ЗаписьJSON.УстановитьСтроку();
ЗаписатьJSON(ЗаписьJSON, ДанныеПакета);
СтрокаJSON = ЗаписьJSON.Закрыть();

// Теперь СтрокуJSON можно записать в текстовый реквизит нашей очереди задач

Для восстановления отбора и последующего чтения набора записей мы используем десериализацию:


// Чтение данных из очереди задач
ЧтениеJSON = Новый ЧтениеJSON;
ЧтениеJSON.УстановитьСтроку(СтрокаJSON);
ДанныеПакета = ПрочитатьJSON(ЧтениеJSON);
ЧтениеJSON.Закрыть();

ИмяРегистра = ДанныеПакета.ИмяРегистра;
СтруктураОтбора = ДанныеПакета.Отбор;

// Воссоздаем набор записей и применяем сохраненный отбор
НаборЗаписей = РегистрыСведений[ИмяРегистра].СоздатьНаборЗаписей();
Для Каждого КлючИЗначение Из СтруктураОтбора Цикл
    НаборЗаписей.Отбор[КлючИЗначение.Ключ].Установить(КлючИЗначение.Значение, Истина);
КонецЦикла;

НаборЗаписей.Прочитать();
// Выполняем отложенную обработку набора данных...

Преимущества метода: Универсальность, простота внедрения, независимость от метаданных конфигурации.

Недостатки: Мы не можем выполнять поиск или группировку по элементам отбора внутри СУБД (например, быстро определить в запросе, есть ли уже в очереди обработка по конкретной номенклатуре), так как данные упакованы в строку или бинарный объект.

Решение 2. Использование системного механизма планов обмена

Если нам требуется гарантированная и производительная регистрация изменений для последующей отправки или обработки, платформа предоставляет мощный встроенный механизм — Планы обмена. Многие разработчики забывают, что планы обмена умеют работать не только со ссылочными типами, но и с наборами записей регистров.

При регистрации изменений набора записей в плане обмена платформа автоматически создает и сохраняет специальный системный объект — РегистрСведенийКлючЗаписи (или аналог для РН). Этот ключ содержит значения всех измерений, однозначно идентифицирующих измененную запись.

Рассмотрим подробнее схему работы:

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

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

Недостатки: В высоконагруженных системах (HighLoad) частая запись в таблицы регистрации изменений планов обмена может приводить к избыточным блокировкам в СУБД. Именно поэтому автор темы искал альтернативные пути решения.

Решение 3. Архитектурный паттерн «Ключи аналитики» (наиболее масштабируемый вариант)

Проанализируем продвинутый подход, который используется в современных типовых конфигурациях фирмы «1С» (например, в «1С:ERP Управление предприятием» или «1С:Управление торговлей 11»). Этот подход идеален для высоконагруженных систем.

Суть паттерна заключается в уходе от хранения множества отдельных измерений в самом регистре сведений и переходе к хранению единого ссылочного измерения — Ключа аналитики.

Рассмотрим реализацию этого паттерна:

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

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

Посмотрим на пример запроса к очереди задач при использовании ключей аналитики:


ВЫБРАТЬ
    ОчередьЗадач.КлючАналитики,
    ОчередьЗадач.ПараметрОбработки
ИЗ
    РегистрСведений.ОчередьЗадач КАК ОчередьЗадач
ГДЕ
    ОчередьЗадач.Статус = ЗНАЧЕНИЕ(Перечисление.СтатусыЗадач.Новая)

Преимущества метода:

Недостатки: Требует серьезного изменения архитектуры метаданных конфигурации и написания дополнительного кода для поиска/создания ключей аналитики при записи движений.

Резюме: какой метод выбрать?

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

← На главную