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