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