Часто в корпоративных системах, таких как 1С:ERP или 1С:Комплексная автоматизация, возникает задача построения отчета, который покажет, когда и каким пользователем был установлен определенный статус документа (например, «К оплате» или «Согласовано»). Проанализируем ситуацию: в системе включено штатное версионирование, и логичным шагом кажется извлечь нужные даты прямо из регистра сведений ВерсииОбъектов. Разберем по шагам, как правильно подойти к этой задаче, с какими подводными камнями можно столкнуться и как написать оптимальный код.
Если мы откроем регистр ВерсииОбъектов в режиме предприятия, мы увидим лишь общую информацию: объект, номер версии, автора и дату. Самих реквизитов документа там нет. Посмотрим, почему так происходит.
Дело в том, что Библиотека стандартных подсистем (БСП) сериализует копию документа и сохраняет её в формате XML или сжатом бинарном формате FastInfoSet. Эти упакованные данные помещаются в ресурс ВерсияОбъекта, который имеет тип ХранилищеЗначения. Следовательно, мы не можем просто обратиться к реквизиту «Статус» обычным запросом к базе данных.
Чтобы вытащить данные, нам необходимо прочитать хранилище значения и десериализовать его. На выходе мы получим настоящий ДокументОбъект (а не ссылку), из которого уже можно будет извлечь значение нужного поля.
Рассмотрим, как можно программно извлечь данные конкретной версии, не изобретая велосипед. В БСП предусмотрены готовые программные интерфейсы для работы с версиями. Если мы хотим перебрать версии документа и найти момент изменения статуса, мы можем использовать специальную функцию:
// Получаем структуру данных конкретной версии документа
ДанныеВерсии = ВерсионированиеОбъектов.РазборВерсии(СсылкаНаДокумент, НомерВерсии);
Этот метод возвращает готовую структуру или объект, с которым можно работать программно. Алгоритм для поиска будет следующим: мы перебираем версии документа, начиная с самой первой. Если в версии (N-1) статус был один, а в версии (N) стал «К оплате», то дата версии (N) — это искомая дата установки статуса.
Для вывода информации пользователю в типовых документах можно использовать встроенные возможности платформы: найдите кнопку с карандашиком «Перейти к отчетам — История изменений» или вызовите форму программно:
ВерсионированиеОбъектовКлиент.ПоказатьИсториюИзменений(СсылкаНаДокумент, ФормаВладелец);
Если нам необходимо получить список дат изменений для большого количества документов (например, для использования в качестве внешнего набора данных в СКД), нам придется сначала сделать выборку из регистра сведений. Разберем важнейшую ошибку, которую допускают разработчики при написании запроса.
Реквизит Объект в регистре ВерсииОбъектов имеет составной тип данных. Если мы попытаемся обратиться к нему через точку, например ВерсииОбъектов.Объект.Ссылка = &Документ, платформа 1С выполнит неявное левое соединение (LEFT JOIN) со всеми таблицами базы данных, входящими в этот составной тип. Это приведет к катастрофическим тормозам и зависанию базы.
Рассмотрим правильный подход к построению запроса. Мы должны использовать оператор ССЫЛКА для ограничения типов и функцию ВЫРАЗИТЬ для явного указания типа документа:
ВЫБРАТЬ
ВерсииОбъектов.Объект,
ВЫРАЗИТЬ(ВерсииОбъектов.Объект КАК Документ.ЗаявкаНаРасходованиеДенежныхСредств).Дата КАК ДатаДокумента,
ВерсииОбъектов.НомерВерсии,
ВерсииОбъектов.АвторВерсии,
ВерсииОбъектов.ДатаВерсии
ИЗ
РегистрСведений.ВерсииОбъектов КАК ВерсииОбъектов
ГДЕ
ВерсииОбъектов.ДатаВерсии >= &ДатаВерсии
И ВерсииОбъектов.Объект ССЫЛКА Документ.ЗаявкаНаРасходованиеДенежныхСредств
И ВерсииОбъектов.Объект = &СсылкаНаДокумент
Обратите внимание: мы используем условие ВерсииОбъектов.Объект = &СсылкаНаДокумент, а не обращаемся через точку к свойству Ссылка. Проверено на практике — такой запрос работает на несколько порядков быстрее.
Несмотря на то, что получить данные из регистра ВерсииОбъектов технически возможно, проанализируем ситуацию с точки зрения архитектуры высоконагруженной системы. Использование штатного версионирования для бизнес-отчетов — не лучшая практика. На это есть несколько веских причин:
ХранилищеЗначения для каждой версии документа — очень ресурсоемкая операция. Если менеджеру нужно строить отчет по тысячам документов за месяц, сервер 1С будет сильно нагружен разбором данных.Как сделать правильно? Если вам важна надежность и скорость работы аналитического отчета, высекайте эти события «в граните». Создайте свой собственный (независимый) регистр сведений ИсторияСтатусовДокументов.
Его структура должна быть простой: в измерениях храните Документ, в ресурсах — Статус, ДатаУстановки и Пользователь. Добавьте небольшую процедуру в подписку на событие документа ПриЗаписи (или ОбработкаПроведения): если статус документа изменился по сравнению со ссылкой в базе данных, делайте запись в ваш новый регистр.
Такой подход позволит вам формировать отчеты мгновенно с помощью простых запросов напрямую к таблице базы данных, не опасаясь, что история будет стерта при плановой очистке версий или база «зависнет» при попытке распаковать тысячи файлов.