Перечитывание данных в 1С:Предприятие — одна из самых востребованных операций при разработке и администрировании систем. Чаще всего она требуется, когда изменения в базе данных (например, через прямые SQL-запросы или внешние системы) не отражаются в текущем сеансе работы. Без правильного вызова перечитывания пользователи могут наблюдать устаревшие данные, что приводит к ошибкам в бизнес-процессах, некорректным отчётам или сбоям в логике работы.
В этой статье мы разберём все доступные способы программного перечитывания — от стандартных методов платформы 1С 8.3 до недокументированных приёмов для сложных сценариев. Особое внимание уделим производительности, безопасности и побочным эффектам, которые могут возникнуть при неправильном использовании этих механизмов. Вы также найдёте готовые кодовые примеры для типовых задач: перечитывание справочников, документов, регистров и даже произвольных наборов данных.
Материал будет полезен как начинающим разработчикам 1С, так и опытным специалистам, столкнувшимся с нестандартными случаями, когда стандартные методы не работают. Все примеры тестировались на актуальных версиях платформы (включая 1С:Предприятие 8.3.22), но некоторые подходы универсальны и применимы к более ранним релизам.
1. Почему данные в 1С не обновляются автоматически?
Платформа 1С:Предприятие использует механизм кэширования данных для ускорения работы приложений. Это означает, что объекты (справочники, документы, регистры) загружаются в оперативную память при первом обращении и хранятся там до завершения сеанса или явного освобождения. Такой подход значительно сокращает количество обращений к базе данных, но имеет обратную сторону: если данные изменились вне текущего сеанса (например, через другой сеанс, фоновое задание или SQL-запрос), пользователь продолжит видеть устаревшую информацию.
Типичные сценарии, когда требуется принудительное перечитывание:
- 🔄 Изменения через прямые SQL-запросы (например, массовое обновление полей через
ВыполнитьЗапрос()без использования объектной модели 1С). - 📊 Обмен данными с внешними системами (веб-сервисы, REST API, файлы XML/JSON), где данные записываются напрямую в базу.
- 👥 Многопользовательский режим, когда один пользователь изменил данные, а другой их не видит.
- 🛠️ Отладка и тестирование, когда требуется сбросить кэш для проверки корректности логики.
Важно понимать, что не все объекты кэшируются одинаково. Например, регистры накопления и регистры сведений могут иметь разные стратегии кэширования в зависимости от настроек конфигурации. Кроме того, некоторые операции (например, Записать() или Провести()) автоматически сбрасывают кэш для текущего объекта, но не для связанных с ним данных.
⚠️ Внимание: Частое принудительное перечитывание может значительно снизить производительность системы, особенно в клиент-серверном варианте работы. Используйте эти методы только когда это действительно необходимо.
2. Стандартные методы перечитывания объектов
Платформа 1С:Предприятие предоставляет несколько встроенных методов для перечитывания данных. Их выбор зависит от типа объекта и контекста выполнения.
2.1. Метод Прочитать() для справочников и документов
Самый простой способ обновить данные текущего объекта — вызвать метод Прочитать(). Он работает для большинства прикладных объектов: справочников, документов, планов обмена и т.д.
// Пример для справочника
СправочникОбъект = Справочники.Номенклатура.НайтиПоНаименованию("Товар 1");
СправочникОбъект.Прочитать(); // Перечитывает все реквизиты и табличные части
// Пример для документа
ДокументОбъект = Документы.РеализацияТоваровУслуг.НайтиПоНомеру("00000001");
ДокументОбъект.Прочитать();
Особенности метода:
- ✅ Перечитывает все реквизиты, включая табличные части и реквизиты формы (если объект привязан к форме).
- ⚠️ Не обновляет связанные объекты (например, если в документе есть ссылка на справочник, сам справочник не перечитается).
- ❌ Не работает для регистров и отчётов — для них нужны другие подходы.
2.2. Метод ПолучитьОбъект() для принудительного создания новой копии
Если объект уже существует в памяти, но требуется гарантированно получить актуальную версию, можно использовать комбинацию ПолучитьСсылку() + ПолучитьОбъект():
СсылкаНаОбъект = Справочники.Контрагенты.НайтиПоНаименованию("ООО Ромашка").Ссылка();
НовыйОбъект = СсылкаНаОбъект.ПолучитьОбъект(); // Создаёт новый экземпляр с актуальными данными
Этот метод полезен, когда:
- 🔄 Нужно сравнить старую и новую версии объекта.
- 🛡️ Требуется избежать побочных эффектов от изменения текущего объекта (например, в транзакциях).
Если вы работаете с формой объекта, после программного перечитывания данных не забудьте вызвать ОбновитьФорму(), чтобы изменения отобразились на экране.
2.3. Перечитывание коллекций объектов
Для массового перечитывания (например, всех строк в табличной части или выборке) используйте метод Прочитать() для всей коллекции:
Выборка = Справочники.Номенклатура.Выбрать();
Пока Выборка.Следующий() Цикл
ТекущийОбъект = Выборка.ПолучитьОбъект();
ТекущийОбъект.Прочитать(); // Перечитывает каждый элемент выборки
КонецЦикла;
⚠️ Внимание: Массовое перечитывание больших выборок может привести к значительной нагрузке на сервер. В клиент-серверном варианте такие операции лучше выполнять в фоновых заданиях.
3. Перечитывание регистров и наборов записей
Регистры (накопления, сведений, бухгалтерии) кэшируются иначе, чем прикладные объекты. Для них стандартные методы вроде Прочитать() не работают. Вместо этого используются специализированные подходы.
3.1. Метод Прочитать() для менеджера регистра
Для перечитывания всего регистра можно использовать менеджер регистра с явным указанием параметров:
МенеджерРегистра = РегистрыСведений.ЦеныНоменклатуры;
МенеджерРегистра.Прочитать(Истина); // Принудительное перечитывание всех данных
Параметры метода Прочитать() для регистров:
| Параметр | Описание | Значение по умолчанию |
|---|---|---|
ПринудительноеОбновление | Игнарировать кэш и читать данные напрямую из БД | Ложь |
ТолькоАктуальные | Читать только актуальные записи (для регистров сведений) | Истина |
ПараметрыЧтения | Дополнительные параметры (например, отборы) | Неопределено |
3.2. Перечитывание набора записей
Если вам нужно обновить конкретный набор записей (например, после массового изменения через запрос), используйте метод Прочитать() для набора записей:
НаборЗаписей = РегистрыСведений.ЦеныНоменклатуры.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.Номенклатура.Установить(Справочники.Номенклатура.НайтиПоНаименованию("Товар 1"));
НаборЗаписей.Прочитать(); // Перечитывает записи с учётом отбора
Для регистров накопления и регистров бухгалтерии логика аналогична, но учитывайте, что перечитывание больших наборов может быть ресурсоёмким.
Что делать если регистр не перечитывается?
Если после вызова Прочитать() данные остаются устаревшими, проверьте:
1. Не блокирует ли данные другая транзакция (используйте НачатьТранзакцию()/ЗафиксироватьТранзакцию()).
2. Не используется ли управляемое блокирование на уровне СУБД (например, в PostgreSQL или MS SQL).
3. Нет ли ошибок в отборах — иногда неверный отбор приводит к пустому набору записей.
4. Продвинутые техники перечитывания
В некоторых случаях стандартные методы не работают или работают неэффективно. Например, при работе с внешними источниками данных, распределёнными базами или после прямых SQL-запросов. Здесь на помощь приходят недокументированные или редко используемые приёмы.
4.1. Использование ОбновитьКэшДанных()
Метод ОбновитьКэшДанных() доступен для некоторых менеджеров объектов и позволяет сбросить кэш без перечитывания всех данных:
Справочники.Номенклатура.ОбновитьКэшДанных(); // Сбрасывает кэш для всего справочника
Этот метод полезен, когда:
- 📈 Нужно освободить память без фактического чтения данных.
- 🔄 Данные изменились внешним образом (например, через SQL или COM-соединение).
4.2. Принудительный сброс кэша через ОчиститьКэш()
Для глобального сброса кэша (например, после массовых операций) можно использовать системный метод:
ОчиститьКэшКонфигурации(); // Сбрасывает кэш метаданных и данных
ОчиститьКэшСеанса(); // Сбрасывает кэш текущего сеанса
⚠️ Внимание: Эти методы затратны по ресурсам и могут привести к временному "подвисанию" интерфейса. Не используйте их в циклах или часто вызываемых процедурах.
4.3. Перечитывание через временные таблицы
Если данные были изменены через Запрос, но не отображаются в объектах, можно использовать временные таблицы для принудительного обновления:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Номенклатура.Ссылка КАК Ссылка
|ИЗ
| Справочник.Номенклатура КАК Номенклатура
|ГДЕ
| Номенклатура.ЭтоГруппа = ЛОЖЬ";
Результат = Запрос.Выполнить();
ВременнаяТаблица = Результат.Выгрузить(); // Принудительное чтение из БД
1. Убедитесь, что стандартные методы не решают задачу
2. Проверьте наличие блокировок в базе данных
3. Оцените влияние на производительность (особенно в клиент-серверном режиме)
4. Протестируйте логику на копии базы данных-->
5. Перечитывание в клиент-серверном и файловом вариантах
Механизмы кэширования и перечитывания данных отличаются в зависимости от варианта работы 1С:Предприятия. Рассмотрим ключевые особенности.
5.1. Файловый вариант
В файловом варианте (.1CD) кэш хранится локально в памяти процесса 1cv8.exe. Особенности:
- 💾 Перечитывание происходит быстрее, так как нет сетевых задержек.
- 🔄 Методы вроде
ОчиститьКэшСеанса()работают мгновенно. - ⚠️ При одновременной работе нескольких пользователей возможны конфликты блокировок.
5.2. Клиент-серверный вариант
В клиент-серверном варианте кэш распределён между сервером 1С:Предприятия и клиентским приложением. Здесь важно учитывать:
- 🌐 Данные могут кэшироваться на сервере и на клиенте отдельно.
- 📡 Методы перечитывания могут требовать дополнительных сетевых запросов.
- 🔒 Блокировки управляются сервером, что может замедлять операции.
Пример кода для клиент-серверного варианта с учётом распределённого кэша:
// На сервере
Процедура ПеречитатьДанныеНаСервере(СсылкаНаОбъект) Экспорт
Объект = СсылкаНаОбъект.ПолучитьОбъект();
Объект.Прочитать(Истина); // Принудительное чтение с сервера
Возврат Объект;
КонецПроцедуры
// На клиенте
Ссылка = Справочники.Контрагенты.НайтиПоНаименованию("ООО Весна").Ссылка();
АктуальныйОбъект = Сервер.ПеречитатьДанныеНаСервере(Ссылка);
5.3. Работа в веб-клиенте и тонком клиенте
В веб-клиенте и тонком клиенте кэширование данных более агрессивное из-за особенностей архитектуры. Здесь рекомендуется:
- 🔄 Использовать
ОбновитьФорму()после программного перечитывания. - 📱 Для мобильного приложения 1С может потребоваться полный рестарт сеанса.
В клиент-серверном варианте всегда проверяйте, на какой стороне (клиент/сервер) выполняется код перечитывания. Неправильное размещение кода может привести к ошибкам или неэффективной работе.
6. Ошибки и побочные эффекты при перечитывании
Неправильное использование методов перечитывания может привести к неожиданным последствиям. Рассмотрим типичные ошибки и способы их избежать.
6.1. Потеря несохранённых изменений
Если объект был изменён в текущем сеансе, но не записан, вызов Прочитать() отменит все несохранённые изменения:
Объект = Справочники.Номенклатура.СоздатьЭлемент();
Объект.Наименование = "Новый товар"; // Изменение не записано
Объект.Прочита(); // Все несохранённые данные будут потеряны!
Чтобы избежать потери данных:
- 💾 Всегда вызывайте
Записать()перед перечитыванием. - 🔄 Используйте
Копировать()для создания резервной копии объекта.
6.2. Зацикливание при рекурсивном перечитывании
Если в обработчике события (например, ПриЗаписи) вызывать Прочитать() для того же объекта, это может привести к бесконечной рекурсии:
Процедура ПриЗаписи(Отказ)
ЭтотОбъект.Прочитать(); // Рекурсивный вызов ПриЗаписи!
КонецПроцедуры
Решение:
- 🚫 Избегайте перечитывания в событиях
ПриЗаписи,ПередЗаписью. - 🔄 Используйте флаги для контроля рекурсии:
Перем флагПеречитывания;
Процедура ПриЗаписи(Отказ)
Если НЕ флагПеречитывания Тогда
флагПеречитывания = Истина;
ЭтотОбъект.Прочитать();
флагПеречитывания = Ложь;
КонецЕсли;
КонецПроцедуры
6.3. Проблемы с транзакциями и блокировками
Если данные заблокированы другой транзакцией, перечитывание может завершиться ошибкой:
// Пример ошибки блокировки
НачатьТранзакцию();
Попытка
Объект.Прочитать(); // Может выдать ошибку, если объект заблокирован
Исключение
Сообщить("Ошибка блокировки: " + ОписаниеОшибки());
ОтменитьТранзакцию();
КонецПопытки;
Способы решения:
- 🔄 Используйте
ПовторитьAttempt()для повторных попыток. - 🕒 Увеличьте таймаут блокировки через настройки СУБД.
⚠️ Внимание: В PostgreSQL и MS SQL настройки блокировок могут отличаться. Например, в PostgreSQL по умолчанию используется более жёсткая модель блокировок, чем в MS SQL.
7. Оптимизация и альтернативные подходы
Перечитывание данных — операция не бесплатная. В некоторых случаях её можно избежать, используя альтернативные подходы.
7.1. Использование событий обновления
Вместо принудительного перечитывания можно подписаться на события изменения данных:
// Подписка на событие изменения справочника
Подписка = ПодписатьсяНаСобытие("СправочникОбъект.ПриИзменении", "ОбновитьДанныеВФорме");
Процедура ОбновитьДанныеВФорме(Источник, Параметры) Экспорт
Если Параметры.Объект.Ссылка = ТекущийОбъект.Ссылка Тогда
ТекущийОбъект.Прочитать();
КонецЕсли;
КонецПроцедуры
7.2. Работа с кэшем через ПараметрыСеанса
Для часто используемых данных можно организовать ручное кэширование в параметрах сеанса:
Процедура ПолучитьАктуальныеДанные()
Если НЕ ЗначениеЗаполнено(ПараметрыСеанса.КэшНоменклатуры) Тогда
ПараметрыСеанса.КэшНоменклатуры = Справочники.Номенклатура.Выбрать();
КонецЕсли;
Возврат ПараметрыСеанса.КэшНоменклатуры;
КонецПроцедуры
// Принудительное обновление кэша
Процедура ОбновитьКэшНоменклатуры()
ПараметрыСеанса.КэшНоменклатуры = Справочники.Номенклатура.Выбрать(Истина); // Истина - принудительное чтение
КонецПроцедуры
7.3. Использование SQL-запросов для обхода кэша
Если данные нужно получить в обход кэша 1С, можно использовать прямые SQL-запросы (только для опытных разработчиков!):
Запрос = Новый Запрос(
"ВЫБРАТЬ
| ТоварКод КАК Код,
| ТоварНаименование КАК Наименование
|ИЗ
| &Таблица1 КАК Товар"
);
Запрос.УстановитьПараметр("Таблица1", Метаданные.Справочники.Номенклатура.ПолноеИмяТаблицы());
Результат = Запрос.Выполнить();
⚠️ Внимание: Прямые SQL-запросы не рекомендуются для регулярного использования, так как они:
- Нарушают целостность объектной модели 1С.
- Могут привести к ошибкам при обновлении конфигурации.
- Требуют глубокого знания структуры базы данных.
Используйте их только в крайних случаях!
8. Практические примеры для типовых задач
Рассмотрим готовые решения для самых распространённых сценариев, где требуется программное перечитывание.
8.1. Перечитывание справочника после массового обновления
После массового изменения данных через запрос:
// 1. Массовое обновление через запрос
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Номенклатура.Ссылка КАК Ссылка
|ИЗ
| Справочник.Номенклатура КАК Номенклатура
|ГДЕ
| НЕ Номенклатура.ПометкаУдаления";
Результат = Запрос.Выполнить();
// 2. Перечитывание всех изменённых объектов
Выборка = Результат.Выбрать();
Пока Выборка.Следующий() Цикл
Объект = Выборка.Ссылка.ПолучитьОбъект();
Объект.Прочитать();
КонецЦикла;
8.2. Перечитывание документа с табличными частями
Если в документе есть табличные части, их тоже нужно перечитать:
ДокументОбъект = Документы.ЗаказПокупателя.НайтиПоНомеру("00000001");
ДокументОбъект.Прочитать(); // Перечитывает шапку и табличные части
// Альтернативно, можно перечитать только табличную часть
ТЧ = ДокументОбъект.Товары;
ТЧ.Прочитать();
8.3. Перечитывание регистра сведений с отбором
Пример для регистра цен:
МенеджерРегистра = РегистрыСведений.ЦеныНоменклатуры;
НаборЗаписей = МенеджерРегистра.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.Номенклатура.Установить(СправочникСсылка);
НаборЗаписей.Отбор.Дата.Установить(ТекущаяДата());
НаборЗаписей.Прочитать(); // Чтение с учётом отбора
8.4. Перечитывание данных в фоновом задании
Для длительных операций лучше использовать фоновые задания:
ФоновоеЗадание = ФоновыеЗадания.Создать("ПеречитатьДанныеВФоне");
ФоновоеЗадание.Параметры.Установить("СсылкаНаОбъект", Объект.Ссылка());
ФоновоеЗадание.Выполнить();
Процедура ПеречитатьДанныеВФоне(Параметры) Экспорт
Объект = Параметры.СсылкаНаОбъект.ПолучитьОбъект();
Объект.Прочитать(Истина); // Принудительное чтение
КонецПроцедуры
Для массового перечитывания данных всегда используйте фоновые задания или распределяйте нагрузку по времени (например, с помощью регламентных заданий).
FAQ: Частые вопросы по перечитыванию данных в 1С
❓ Почему после вызова Прочитать() данные всё равно устаревшие?
Это может происходить по нескольким причинам:
- 🔄 Данные заблокированы другой транзакцией (проверьте через
ТекущиеТранзакции()). - 📋 Вы перечитываете не тот объект (например, копию вместо оригинала).
- 🗃️ В клиент-серверном варианте кэш не синхронизирован между сервером и клиентом (попробуйте
ОчиститьКэшСеанса()). - 🛠️ Если используете SQL-запросы, изменения могли не попасть в объектную модель 1С (требуется перезагрузка сеанса).
Для диагностики добавьте в код вывод версии объекта до и после перечитывания:
Сообщить("Версия до: " + Объект.ВерсияДанных());
Объект.Прочитать();
Сообщить("Версия после: " + Объект.ВерсияДанных());
❓ Как перечитать данные в управляемой форме?
В управляемых формах после программного перечитывания объекта нужно явно обновить форму:
// 1. Перечитать объект
ЭтотОбъект.Объект.Прочитать();
// 2. Обновить форму
ЭтотОбъект.ОбновитьФорму();
// Альтернативно, можно обновить только нужные реквизиты:
ЭтотОбъект.ОбновитьРеквизиты();
Если форма содержит динамический список, его тоже нужно обновить:
ЭтотОбъект.ЭлементыФормы.СписокТоваров.Обновить();
❓ Можно ли перечитать данные для всех пользователей одновременно?
Нет, в 1С:Предприятие нет встроенного механизма для массового сброса кэша во всех сеансах. Однако есть обходные пути:
- 🔄 Рестарт сервера 1С — сбросит кэш для всех пользователей, но приведёт к разрыву соединений.
- 📢 Уведомление пользователей о необходимости перезагрузки сеанса (через
ПоказатьОповещениеПользователя()). - 🛠️ Фоновое задание, которое последовательно обходит активные сеансы (требует прав администратора).
Пример кода для оповещения пользователей:
Для Каждого Сеанс Из Сеансы Индекс По i Цикл
ПоказатьОповещениеПользователя(
Сеанс.УникальныйИдентификатор,
"Обновите данные",
"Перезагрузите сеанс для актуализации данных",
10 // Таймаут в секундах
);