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