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