В практике разработки на платформе 1С:Предприятие 8.3 программисты часто сталкиваются с ситуацией, когда код выполняется без ошибок, данные в базе данных обновляются (что подтверждается консолью запросов), но пользователь в интерфейсе видит старые значения. Особенно остро эта проблема проявляется в сложных конфигурациях, таких как Зарплата и кадры государственного учреждения (ЗиКГУ) 3.1 или Зарплата и управление персоналом (ЗУП) 3.1.
В данной статье мы подробно разберем, почему при программном изменении элемента справочника (на примере штатного расписания) форма может игнорировать внесенные правки, и как правильно организовать обновление данных, чтобы избежать конфликтов с кэшем платформы и внутренней логикой программы.
Рассмотрим стандартную ситуацию. Разработчик пишет код для обновления реквизита СтатьяФинансирования в справочнике ШтатноеРасписание:
&НаСервере
Процедура ЗаписатьЗначениеНаСервере()
// Получаем объект из ссылки
Док = Объект.ЭлементСправочника.ПолучитьОбъект();
// Находим нужное значение статьи
Док.СтатьяФинансирования = Справочники.СтатьиФинансированияЗарплата.НайтиПоКоду("СГ");
// Записываем объект в базу
Док.Записать();
КонецПроцедуры
После выполнения этого кода в консоли запросов мы видим, что поле _FLD8625RREF (соответствующее статье финансирования) обновилось. Однако при открытии карточки позиции штатного расписания поле остается пустым или содержит старое значение. Проанализируем причины этого явления, которых может быть несколько.
В современных конфигурациях по учету кадров справочник ШтатноеРасписание часто является лишь «оболочкой». Если в настройках программы включено ведение истории изменений штатного расписания, основные данные (оклады, надбавки, статьи финансирования) хранятся не только в самом справочнике, но и в периодическом регистре сведений ИсторияИспользованияШтатногоРасписания.
Выясним логику работы формы: при открытии элемента штатного расписания система часто выполняет программное заполнение реквизитов формы, обращаясь к «срезу последних» этого регистра. Если вы изменили реквизит только в справочнике, но не создали соответствующую запись в регистре сведений или не обновили существующую, форма при открытии просто перезапишет значение в поле ввода данными из регистра. В итоге пользователь видит не то, что записано в объекте СправочникОбъект, а то, что актуально по мнению учетного регистра.
Иногда программисты пытаются обойти проверки в модуле объекта, устанавливая флаг ОбменДанными.Загрузка = Истина. Рассмотрим пример:
Док = Объект.ЭлементСправочника.ПолучитьОбъект();
Док.ОбменДанными.Загрузка = Истина;
Док.СтатьяФинансирования = Справочники.СтатьиФинансированияЗарплата.НайтиПоКоду("СГ");
Док.Записать();
Важный момент: установка этого флага отключает большинство обработчиков событий ПередЗаписью и ПриЗаписи. Если в этих обработчиках прописана синхронизация данных справочника с теми самыми регистрами сведений, то при Загрузка = Истина синхронизация не произойдет. База данных окажется в рассогласованном состоянии: в справочнике одно значение, в регистре — другое.
Особое внимание стоит уделить версии платформы. В ветке 8.3.22 (например, релиз 1923) были зафиксированы ошибки, связанные с некорректным обновлением кэша представлений объектов на стороне клиента. Платформа кэширует текстовое представление ссылок и значения некоторых полей для ускорения работы интерфейса.
Если данные изменены программно на сервере, клиентское приложение может не узнать об этом и продолжать показывать старое значение из своего локального кэша. В этом случае даже интерактивное нажатие кнопки «Перечитать» может не дать эффекта, если платформа считает кэш актуальным.
Чтобы гарантированно обновить данные и отобразить их в интерфейсе, выполним следующую последовательность действий.
Если вы работаете с конфигурацией, где используется история штатного расписания, правильнее всего изменять данные через специализированные документы (например, «Изменение штатного расписания»). Если же необходимо прямое программное изменение, убедитесь, что вы обновляете и справочник, и связанные регистры сведений.
Чтобы клиентские формы «узнали», что данные в базе изменились, необходимо использовать метод ОповеститьОбИзменении. Это заставляет платформу сбросить кэш для конкретной ссылки.
&НаКлиенте
Процедура ЗаписатьИОбновить()
ЗаписатьЗначениеНаСервере();
// Оповещаем все открытые формы о том, что объект изменился
ОповеститьОбИзменении(Объект.ЭлементСправочника);
КонецПроцедуры
Если форма элемента уже открыта, и вы программно меняете данные «под ней» (например, из другой обработки), в самой форме полезно вызвать метод Прочитать(). Он принудительно перечитывает данные объекта из базы данных, минуя кэш.
// В контексте формы элемента
ЭтаФорма.Прочитать();
Как показала практика решения подобных проблем на форумах, переход с проблемных релизов (типа 8.3.22.1923) на более стабильные (например, 8.3.23 и выше) часто устраняет странности с отображением данных. В новых версиях исправлены механизмы инвалидации кэша, что позволяет методу Прочитать() и команде «Перечитать» работать корректно в 100% случаев.
Проанализировав ситуацию, мы можем сделать вывод: если значение в справочнике записано, но не отображается, следует выполнить три проверки:
ПриЧтенииНаСервере или ПриСозданииНаСервере.ОповеститьОбИзменении() на клиенте после записи на сервере.Прочитать() не помогает), стоит рассмотреть вопрос обновления платформы до актуального релиза.Соблюдение этих правил поможет избежать «мистических» ошибок при программном управлении данными в сложных корпоративных системах на базе 1С.