В процессе разработки на платформе 1С:Предприятие 8.3 программисты часто сталкиваются с ситуацией, когда данные в табличной части документа не обновляются мгновенно после программного изменения связанных объектов. Особенно остро эта проблема проявляется, если в колонках таблицы отображаются реквизиты ссылочных данных (так называемый вывод «через точку»). Давайте подробно разберем, почему стандартные методы обновления не всегда эффективны и как правильно заставить интерфейс отобразить актуальную информацию.
Представим рабочую ситуацию: в табличной части документа есть колонка Заявление (ссылка на другой документ) и колонка Статус, которая является реквизитом этого самого заявления. Когда мы программно получаем объект заявления на сервере, меняем его статус и записываем, база данных обновляется. Однако форма основного документа, открытая у пользователя, продолжает показывать старый статус.
Почему так происходит? Дело в том, что платформа 1С использует клиентское кэширование для оптимизации производительности. Данные, полученные «через точку» от навигационной ссылки, кэшируются на стороне клиента. Метод ЭтаФорма.Прочитать() перечитывает только данные самого основного объекта, но не сбрасывает кэш связанных ссылок. Методы ОбновитьОтображениеДанных() или Элементы.ИмяТаблицы.Обновить() лишь перерисовывают элементы управления, но не инициируют повторный запрос данных из базы, если платформа считает кэш актуальным.
Самым простым и эффективным способом решить проблему является использование встроенного механизма оповещений платформы. Нам необходимо явно «сказать» клиентскому приложению, что данные определенного типа объектов изменились и кэш нужно сбросить. Для этого используется метод ОповеститьОбИзменении().
Рассмотрим пример кода, который должен быть выполнен на клиенте после завершения серверной процедуры модификации документов:
// На стороне клиента, после вызова процедуры изменения статусов
&НаКлиенте
Процедура ИзменитьСтатусыИОбновить(Команда)
// Вызываем серверный метод, где происходит изменение объектов
ИзменитьСтатусыНаСервере();
// Оповещаем систему о том, что данные типа "Заявление" изменились
// Это заставит форму перечитать все связанные реквизиты данного типа
ОповеститьОбИзменении(Тип("ДокументСсылка.Заявление"));
КонецПроцедуры
Метод ОповеститьОбИзменении() принимает в качестве параметра либо конкретную ссылку, либо тип объекта. Передача типа объекта — более универсальный подход, особенно если вы изменили множество строк в табличной части (например, 5000 строк, как упоминал автор темы). Это заставит систему обновить все отображения документов данного типа во всех открытых формах сеанса.
Если обновление по типу кажется слишком «тяжелым» для системы (например, в базе одновременно открыто очень много форм), можно использовать механизм адресного оповещения. Рассмотрим, как это реализовать по шагам.
Шаг 1. На клиенте после изменения данных вызываем метод Оповестить(), передавая в него имя события и массив измененных ссылок.
&НаКлиенте
Процедура ПослеИзмененияДанных()
МассивСсылок = ПолучитьМассивИзмененныхСсылокНаСервере();
Оповестить("ОбновлениеСтатусовЗаявлений", МассивСсылок, ЭтаФорма);
КонецПроцедуры
Шаг 2. В самой форме, где расположена табличная часть, создаем обработчик события ОбработкаОповещения.
&НаКлиенте
Процедура ОбработкаОповещения(ИмяСобытия, Параметр, Источник)
Если ИмяСобытия = "ОбновлениеСтатусовЗаявлений" Тогда
// Здесь мы можем либо обновить всю форму
ЭтаФорма.ОбновитьОтображениеДанных();
// Либо, если данных очень много, вызвать ОповеститьОбИзменении для конкретных ссылок из массива Параметр
Для Каждого СсылкаИзСписка Из Параметр Цикл
ОповеститьОбИзменении(СсылкаИзСписка);
КонецЦикла;
КонецЕсли;
КонецПроцедуры
Когда в табличной части более 5000 строк, процесс обновления может занимать значительное время. Разберем несколько советов по оптимизации:
Оповестить() и ОповеститьОбИзменении() являются методами глобального контекста клиентского приложения. Они недоступны в модуле менеджера или модуле объекта. Всегда возвращайте управление на клиент и вызывайте их один раз после выполнения всех серверных операций.ДинамическийСписок с произвольным запросом. Динамические списки имеют встроенный механизм отслеживания изменений в базе данных и обновляются автоматически без принудительных вызовов кода (в большинстве случаев).ОповеститьОбИзменении().Часто программисты пытаются решить проблему через Элементы.ТабличнаяЧасть.Обновить(). Выясним, почему это не помогает: данный метод относится к визуальному представлению элемента формы. Он заставляет таблицу перерисовать строки, которые уже находятся в памяти клиента. Но так как кэш ссылочных данных (тех, что «через точку») еще не сброшен, система просто отрисует те же самые старые значения. Только ОповеститьОбИзменении() дает платформе команду признать кэш невалидным и запросить новые данные с сервера при следующей отрисовке.
Резюмируем: для быстрого и гарантированного обновления данных в управляемых формах при программном изменении объектов всегда используйте связку: Серверная модификация -> Возврат на клиент -> ОповеститьОбИзменении(Тип).