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