Как обновить данные в форме 1С при создании новых документов, если подтягиваются старые значения из справочника?

Программист 1С v8.3 (Управляемые формы)
← На главную

В процессе разработки в среде 1С:Предприятие 8 программисты часто сталкиваются с ситуацией, когда данные, измененные одним документом, не сразу становятся "видимыми" для другого документа или формы. Рассмотрим типичный сценарий: вы создаете документ, который меняет реквизиты в справочнике (например, наименование или ответственного сотрудника), проводите его, а затем сразу создаете второй аналогичный документ. К вашему удивлению, при попытке подтянуть данные того же элемента справочника во второй документ, система отображает старые значения, которые были актуальны до проведения первого документа. Проблема исчезает только после перезапуска сеанса или через некоторое время.

Давайте проанализируем, почему это происходит, разберем механизмы работы платформы и выясним, как гарантированно получать актуальные данные из базы данных.

Причина проблемы: Объектный кэш и разыменование ссылок

Главная причина кроется в так называемом объектном кэше платформы 1С. Когда мы работаем с данными через объектную модель (используя ссылки и обращение к их реквизитам "через точку"), платформа старается оптимизировать производительность. Чтобы не обращаться к серверу баз данных (SQL) при каждом чтении реквизита, 1С сохраняет данные объекта в локальной памяти (кэше) текущего сеанса.

Рассмотрим код, который часто приводит к подобным ошибкам:


&НаСервере
Функция НайтиТМЦПоИнвентарномуНомеру(ИнвНомер)
    // Использование встроенного метода поиска
    СсылкаНаОбъект = Справочники.Номенклатура.НайтиПоРеквизиту("ИнвНомер", ИнвНомер);
    Возврат СсылкаНаОбъект;
КонецФункции

&НаКлиенте
Процедура ПриИзмененииИнвНомера(Команда)
    Объект.ТМЦ = НайтиТМЦПоИнвентарномуНомеру(Объект.ИнвНомер);
    // Разыменование ссылки через точку - источник проблемы
    ИмяОбъекта = Объект.ТМЦ.Наименование; 
    Сотрудник = Объект.ТМЦ.Сотрудник;
КонецПроцедуры

В этом примере метод НайтиПоРеквизиту возвращает только ссылку. Однако, как только мы пишем Объект.ТМЦ.Наименование, происходит неявное обращение к базе данных для получения всех полей объекта. Если этот объект уже считывался ранее в этом сеансе или если клиентское приложение еще не получило уведомление об обновлении данных от сервера, платформа подставит значение из кэша. В результате пользователь видит старую информацию, хотя в самой базе данных (на диске) значения уже изменены первым документом.

Решение №1: Использование запросов (рекомендуемый способ)

Самый надежный способ обойти кэширование — использовать объект Запрос. Запросы в 1С всегда обращаются напрямую к таблицам СУБД, игнорируя любые локальные кэши ссылок. Это гарантирует получение самой "свежей" информации на момент выполнения кода.

Разберем, как переписать функцию поиска, чтобы она работала корректно:


&НаСервере
Функция ПолучитьАктуальныеДанныеТМЦ(ИнвНомер) Экспорт
    
    РезультатСтруктура = Новый Структура("Ссылка, Наименование, Сотрудник", Неопределено, "", "");
    
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |   Номенклатура.Ссылка КАК Ссылка,
        |   Номенклатура.Наименование КАК Наименование,
        |   Номенклатура.Сотрудник КАК Сотрудник
        |ИЗ
        |   Справочник.Номенклатура КАК Номенклатура
        |ГДЕ
        |   Номенклатура.ИнвНомер = &ИнвНомер";
        
    Запрос.УстановитьПараметр("ИнвНомер", ИнвНомер);
    
    Выборка = Запрос.Выполнить().Выбрать();
    
    Если Выборка.Следующий() Тогда
        РезультатСтруктура.Ссылка = Выборка.Ссылка;
        РезультатСтруктура.Наименование = Выборка.Наименование;
        РезультатСтруктура.Сотрудник = Выборка.Сотрудник;
    КонецЕсли;
    
    Возврат РезультатСтруктура;
    
КонецФункции

Использование этого метода позволяет нам получить структуру с актуальными значениями полей напрямую из базы. Мы не обращаемся к реквизитам "через точку" от ссылки, а значит, исключаем влияние кэша.

Решение №2: Принудительное обновление объекта

Если вам все же необходимо работать именно с объектом справочника, можно воспользоваться методом ПолучитьОбъект(). В отличие от простого обращения к реквизиту ссылки, вызов Ссылка.ПолучитьОбъект() на сервере заставляет платформу перечитать данные из базы.

Важный нюанс: этот метод более ресурсоемкий, чем запрос, так как система считывает абсолютно все реквизиты объекта и все его табличные части. Используйте его только в том случае, если вам действительно нужно изменять данные объекта или если реквизитов очень много.


&НаСервере
Функция ПроверитьОбъект(Ссылка)
    // Метод ПолучитьОбъект() игнорирует кэш и читает данные из БД
    ОбъектСправочника = Ссылка.ПолучитьОбъект();
    Если ОбъектСправочника <> Неопределено Тогда
        Возврат ОбъектСправочника.Наименование;
    КонецЕсли;
    Возврат "";
КонецФункции

Решение №3: Метод ОповеститьОбИзменении

В платформе существует специальный механизм для "сброса" кэша — метод ОповеститьОбИзменении(Ссылка). Когда первый документ записывает изменения в справочник, программно вызвав этот метод, вы даете системе сигнал: "Данные по этой ссылке устарели, их нужно перечитать во всех открытых формах".

Рассмотрим, где его применить:

  1. В модуле документа, который меняет справочник, в процедуре ПриЗаписи или ПослеЗаписи на клиенте.
  2. Вызовите ОповеститьОбИзменении(Объект.ТМЦ);.

Это заставит другие формы (в том числе форму нового документа) обновить отображаемые данные, если они связаны с этой ссылкой. Однако стоит помнить, что в многопользовательской среде этот механизм не всегда срабатывает мгновенно между разными сеансами пользователей, поэтому использование запроса (Решение №1) остается приоритетным.

Почему НайтиПоРеквизиту работает именно так?

Проанализируем работу метода НайтиПоРеквизиту. С точки зрения системы это удобная "обертка" над запросом, которая возвращает ссылку. Но проблема не в самом поиске, а в том, что разработчики часто забывают: ссылка — это всего лишь уникальный идентификатор (GUID). Сами данные (наименование, код и т.д.) "приезжают" с сервера только тогда, когда вы к ним обращаетесь. И вот в этот момент вступает в силу механизм кэширования. Если вы создаете документы в одном и том же сеансе один за другим, кэш просто не успевает обновиться.

Подведем итоги:

  1. Избегайте обращения к реквизитам Ссылка.Реквизит в критически важных местах, где данные могут быстро меняться.
  2. Для получения актуальных данных всегда используйте Запрос.
  3. Присваивайте переменным осмысленные имена (например, АктуальнаяНоменклатура вместо ПИН), чтобы код был читаемым и легче поддавался отладке.
  4. Помните о разделении клиентского и серверного кэша — данные на сервере могут быть уже обновлены, в то время как клиентская форма все еще хранит старую копию.

Используя эти правила, вы обеспечите стабильную работу системы и исключите появление "фантомных" данных в документах ваших пользователей.

← На главную