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