Присвоение значения реквизиту в 1С 8.3: объект, табличная часть, константа, регистр и форма
Содержание
Чтобы присвоить значение реквизиту в 1С, нужен объект, а не ссылка: Объект = Ссылка.ПолучитьОбъект(); Объект.Комментарий = "Текст"; Объект.Записать();. Внутри модуля самого объекта реквизит доступен прямо по имени: Комментарий = "Текст";. Без вызова Записать() новое значение живёт только в памяти и в базу не попадёт.
Способ зависит от того, где хранится значение. Реквизит справочника или документа меняют через объект, строку табличной части — через коллекцию строк, константу — методом Установить(), запись регистра сведений — через менеджер записи или набор записей. На форме работают с реквизитом формы Объект и не трогают базу до нажатия «Записать».
| Что меняем | Как присваиваем | Как сохраняем |
|---|---|---|
| Реквизит справочника/документа | Объект.Реквизит = Значение | Объект.Записать() |
| Строка табличной части | Строка.Колонка = Значение | Записью владельца |
| Константа | Константы.Имя.Установить(Значение) | Сразу при вызове |
| Регистр сведений | МенеджерЗаписи.Ресурс = Значение | МенеджерЗаписи.Записать() |
| Реквизит на форме | Объект.Реквизит = Значение | Пользователь записывает форму |
Базовое присваивание значения реквизиту в модуле объекта
Оператор присваивания во встроенном языке один — знак =. Слева стоит реквизит, справа выражение. Точка с запятой в конце обязательна.
В модуле объекта (документа, справочника, обработки) реквизиты видны как переменные. Префикс ЭтотОбъект. можно писать, а можно опускать:
Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
Комментарий = "Создан автоматически";
ЭтотОбъект.Ответственный = Пользователи.ТекущийПользователь();
СуммаДокумента = Товары.Итог("Сумма");
КонецПроцедуры
В обработчике ПередЗаписью вызывать Записать() не нужно: платформа и так пишет объект после обработчика. Повторный вызов внутри него приведёт к рекурсии.
Пользователи.ТекущийПользователь() — функция Библиотеки стандартных подсистем. Если её в конфигурации нет, текущего пользователя получают иначе, например через параметр сеанса, принятый в вашей конфигурации.
Где удобно присваивать значения в модуле объекта:
- 📝
ОбработкаЗаполнения— начальные значения при создании нового документа или при вводе на основании; - 🧮
ПередЗаписью— расчётные реквизиты: итоговая сумма, номер версии, дата изменения; - ✅
ОбработкаПроверкиЗаполнения— не присваивание, а проверка, о ней ниже.
Пример начального заполнения нового документа:
Процедура ОбработкаЗаполнения(ДанныеЗаполнения, ТекстЗаполнения, СтандартнаяОбработка)
Если Не ЗначениеЗаполнено(Дата) Тогда
Дата = ТекущаяДатаСеанса();
КонецЕсли;
Если ТипЗнч(ДанныеЗаполнения) = Тип("Структура") Тогда
ЗаполнитьЗначенияСвойств(ЭтотОбъект, ДанныеЗаполнения);
КонецЕсли;
КонецПроцедуры
Проверка ЗначениеЗаполнено здесь защищает от затирания даты, которую уже передали при создании документа.
Как присвоить реквизиту значение из другого модуля и записать объект
Чаще всего значение меняют «снаружи»: из общего модуля, обработки, регламентного задания. Тогда порядок такой:
- Получите ссылку на элемент — из запроса, поиском или из параметра.
- Вызовите
ПолучитьОбъект(). Метод работает только на сервере. - Присвойте значения реквизитам объекта.
- Вызовите
Записать(). Для документа можно указать режим записи.
&НаСервере
Процедура УстановитьКомментарий(ДокументСсылка, Текст)
ДокОбъект = ДокументСсылка.ПолучитьОбъект();
ДокОбъект.Комментарий = Текст;
ДокОбъект.Записать(РежимЗаписиДокумента.Запись);
КонецПроцедуры
Если документ проведён и от изменённого реквизита зависят движения (сумма, склад, счёт), записывайте его в режиме РежимЗаписиДокумента.Проведение. Иначе реквизит в шапке изменится, а движения в регистрах останутся старыми, и отчёты разойдутся с документом. Для реквизитов вроде комментария или ответственного достаточно обычной записи.
Самая частая ошибка новичка — присвоить значение реквизиту ссылки:
ДокументСсылка.Комментарий = "Текст"; // ошибка
Ссылка в 1С только читает данные. Платформа ответит Поле объекта недоступно для записи. Нужен именно объект.
Массовое изменение через ПолучитьОбъект() + Записать() запускает все подписки на события, проверки и перепроведение. На тысяче документов это долго и может поменять движения. Перед групповой обработкой сделайте резервную копию базы.
Если нужно переписать реквизит без бизнес-логики (например, при загрузке данных из другой базы), используют режим обмена:
ДокОбъект.ОбменДанными.Загрузка = Истина;
ДокОбъект.Записать();
В этом режиме не выполняются проверки заполнения и большая часть кода обработчиков, которые проверяют этот флаг. Применяйте его осознанно: ошибочные данные тоже запишутся.
Табличные части и коллекции значений: присваивание по строкам
Реквизит табличной части принадлежит конкретной строке. Сначала получаете строку, потом присваиваете.
Новая строка:
НоваяСтрока = ДокОбъект.Товары.Добавить();
НоваяСтрока.Номенклатура = НоменклатураСсылка;
НоваяСтрока.Количество = 10;
НоваяСтрока.Цена = 150;
НоваяСтрока.Сумма = НоваяСтрока.Количество * НоваяСтрока.Цена; // 1500
Все существующие строки — в цикле:
Для Каждого СтрокаТЧ Из ДокОбъект.Товары Цикл
СтрокаТЧ.Сумма = СтрокаТЧ.Количество * СтрокаТЧ.Цена;
КонецЦикла;
Строка по номеру: индекс начинается с нуля. ДокОбъект.Товары[0].Цена = 200; меняет первую строку. Обращение к несуществующему индексу вызовет ошибку, поэтому сначала проверьте Количество().
Поиск строки по значению:
Найденные = ДокОбъект.Товары.НайтиСтроки(Новый Структура("Номенклатура", НоменклатураСсылка));
Для Каждого СтрокаТЧ Из Найденные Цикл
СтрокаТЧ.Цена = 180;
КонецЦикла;
Изменения табличной части сохраняются вместе с объектом. Отдельного Записать() у неё нет.
Для коллекций в памяти — таблицы значений, структуры, соответствия — правила похожи, но писать в базу ничего не нужно:
| Коллекция | Как присвоить |
|---|---|
| Таблица значений | Строка.Колонка = Значение или ТЗ.ЗаполнитьЗначения(0, "Скидка") |
| Структура | Структура.Вставить("Ключ", Значение) или Структура.Ключ = Значение для существующего ключа |
| Соответствие | Соответствие.Вставить(Ключ, Значение) |
| Массив | Массив[0] = Значение или Массив.Добавить(Значение) |
Когда нужно перенести сразу много полей с одинаковыми именами, выручает ЗаполнитьЗначенияСвойств:
ЗаполнитьЗначенияСвойств(НоваяСтрока, СтрокаИсточник);
ЗаполнитьЗначенияСвойств(ДокОбъект, ДанныеЗаполнения, "Организация, Контрагент");
Второй параметр — откуда берём, третий — список свойств через запятую. Четвёртый параметр — исключения: какие свойства не копировать. Он пригодится, когда у источника и приёмника совпадают служебные поля вроде Номер, Дата или Ответственный, а переносить их не нужно.
Константы и регистры сведений: где значение хранится отдельно от объекта
Константа
Константа хранит одно значение на всю базу. Присвоить его проще всего методом Установить(). Запись происходит сразу, без отдельного Записать():
Константы.ИспользоватьВалютныйУчет.Установить(Истина);
Значение = Константы.ИспользоватьВалютныйУчет.Получить();
Имя константы бывает другим — смотрите ветку Константы в дереве конфигурации. Второй способ — менеджер значения. Он нужен, если важно, чтобы сработали обработчики ПередЗаписью и ПриЗаписи модуля менеджера значения константы:
МенеджерЗначения = Константы.ИспользоватьВалютныйУчет.СоздатьМенеджерЗначения();
МенеджерЗначения.Значение = Истина;
МенеджерЗначения.Записать();
Функциональные опции часто построены на константах. После изменения такой константы интерфейс у пользователей обновится не сразу, а после перезапуска сеанса или обновления повторно используемых значений.
Регистр сведений
Здесь значение хранится не в одном поле, а в записи, которая определяется измерениями (и периодом, если регистр периодический). Для одной записи удобен менеджер записи:
МенеджерЗаписи = РегистрыСведений.КурсыВалют.СоздатьМенеджерЗаписи();
МенеджерЗаписи.Период = НачалоДня(ТекущаяДатаСеанса());
МенеджерЗаписи.Валюта = ВалютаСсылка;
МенеджерЗаписи.Курс = 92.5;
МенеджерЗаписи.Кратность = 1;
МенеджерЗаписи.Записать();
Если запись с таким периодом и измерениями уже есть, Записать() её заменит: параметр замещения по умолчанию равен Истина.
Для нескольких записей сразу используют набор записей с отбором:
Набор = РегистрыСведений.КурсыВалют.СоздатьНаборЗаписей();
Набор.Отбор.Валюта.Установить(ВалютаСсылка);
Набор.Прочитать();
Для Каждого Запись Из Набор Цикл
Запись.Кратность = 1;
КонецЦикла;
Набор.Записать();
Набор без отбора при записи заменит весь регистр. Если вызвать Записать() у пустого набора без установленного отбора, все записи регистра будут удалены. Всегда ставьте отбор перед записью.
Регистр, подчинённый регистратору, напрямую так не пишут: его записи формирует документ при проведении. Значение там меняют через сам документ.
Присвоение значения реквизиту на форме
На управляемой форме данные объекта лежат в основном реквизите формы, обычно он называется Объект. Присваивание на клиенте меняет только форму, в базу ничего не пишется, пока пользователь не нажмёт «Записать»:
&НаКлиенте
Процедура КонтрагентПриИзменении(Элемент)
Объект.Договор = Неопределено;
Объект.Комментарий = "Контрагент изменён";
Модифицированность = Истина;
КонецПроцедуры
Флаг Модифицированность нужен, чтобы форма при закрытии спросила о сохранении. При программном изменении данных он не всегда ставится сам.
Свои реквизиты формы (не из Объект) присваиваются по имени: ПериодОтчета = ТекущаяДата(); — на клиенте или на сервере, без разницы.
На сервере формы иногда нужно поработать с настоящим объектом: вызвать его экспортный метод. Тогда используют пару функций:
&НаСервере
Процедура ПересчитатьНаСервере()
ДокОбъект = РеквизитФормыВЗначение("Объект");
ДокОбъект.ПересчитатьСуммы(); // экспортная процедура модуля объекта
ЗначениеВРеквизитФормы(ДокОбъект, "Объект");
КонецПроцедуры
Управление интерфейсом — это тоже присваивание, только свойствам элементов, а не данных:
- 👁
Элементы.Договор.Видимость = Ложь;— скрыть поле; - 🔒
Элементы.Договор.ТолькоПросмотр = Истина;— запретить ввод; - 🚫
Элементы.Договор.Доступность = Ложь;— сделать поле серым.
Обратите внимание на разницу: Объект.Договор — данные, Элементы.Договор — поле на экране. Перепутать их — классическая причина ошибки Поле объекта не обнаружено.
Ссылочные и составные типы: что можно положить в реквизит
Реквизит ссылочного типа ждёт ссылку, а не строку с наименованием. Типичные способы получить нужное значение:
- 🔎
Справочники.Валюты.НайтиПоКоду("643")— поиск по коду; - 🔎
Справочники.Контрагенты.НайтиПоНаименованию("Ромашка", Истина)— точное совпадение; - 📌
Справочники.ЕдиницыИзмерения.Штука— предопределённый элемент (имя смотрите в конфигурации); - 📌
Перечисления.ВидыОпераций.Поступление— значение перечисления на сервере; - 💻
ПредопределенноеЗначение("Перечисление.ВидыОпераций.Поступление")— то же на клиенте; - ⭕
Справочники.Контрагенты.ПустаяСсылка()— очистить реквизит.
НайтиПоКоду и НайтиПоНаименованию при неудаче возвращают пустую ссылку, а не Неопределено. Проверяйте результат через ЗначениеЗаполнено():
Валюта = Справочники.Валюты.НайтиПоКоду("840");
Если Не ЗначениеЗаполнено(Валюта) Тогда
ВызватьИсключение "Валюта с кодом 840 не найдена";
КонецЕсли;
ДокОбъект.ВалютаДокумента = Валюта;
Составной тип — реквизит, который может хранить значения разных типов. Например, «Контрагент или Физическое лицо», или «Строка или Число». Присвоить можно значение любого из разрешённых типов. Перед обработкой полезно узнать, что лежит внутри:
Если ТипЗнч(Объект.Получатель) = Тип("СправочникСсылка.Контрагенты") Тогда
// логика для контрагента
КонецЕсли;
Если присвоить значение не того типа, платформа приведёт его к типу реквизита. Несовместимое значение превратится в пустое — без ошибки и без сообщения. Строка длиннее, чем задано в свойствах реквизита, обрежется. Привести значение явно можно так:
ОписаниеТипаСуммы = Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(15, 2));
Сумма = ОписаниеТипаСуммы.ПривестиЗначение("1234.567"); // 1234.57
Пустое значение для очистки реквизита у каждого типа своё:
| Тип | Пустое значение |
|---|---|
| Число | 0 |
| Строка | "" |
| Дата | '00010101' или Дата(1, 1, 1) |
| Булево | Ложь |
| Ссылка | ПустаяСсылка() соответствующего менеджера |
| Составной тип | Неопределено |
Проверка значения и обработка ошибок при записи
Присвоить можно что угодно, но запись должна пройти проверки. Ошибки ловят тремя механизмами.
1. Проверка заполнения. Обработчик ОбработкаПроверкиЗаполнения в модуле объекта вызывается при интерактивной записи и при явном вызове ПроверитьЗаполнение():
Процедура ОбработкаПроверкиЗаполнения(Отказ, ПроверяемыеРеквизиты)
Если СуммаДокумента < 0 Тогда
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = "Сумма документа не может быть отрицательной";
Сообщение.Поле = "СуммаДокумента";
Сообщение.УстановитьДанные(ЭтотОбъект);
Сообщение.Сообщить();
Отказ = Истина;
КонецЕсли;
КонецПроцедуры
При программной записи через Записать() эта проверка сама не запускается. Если она нужна, вызовите ДокОбъект.ПроверитьЗаполнение() перед записью и анализируйте результат.
2. Отказ в ПередЗаписью. Установка Отказ = Истина отменяет запись. Код, который вызывал Записать(), получит исключение.
3. Попытка — Исключение. Вокруг записи в общих модулях и обработках:
Попытка
ДокОбъект.Заблокировать();
ДокОбъект.Комментарий = Текст;
ДокОбъект.Записать();
Исключение
ТекстОшибки = ПодробноеПредставлениеОшибки(ИнформацияОбОшибке());
ЗаписьЖурналаРегистрации("Изменение реквизита", УровеньЖурналаРегистрации.Ошибка, , ДокОбъект.Ссылка, ТекстОшибки);
КонецПопытки;
Заблокировать() ставит объектную блокировку: если документ сейчас открыт и редактируется у другого пользователя, вы сразу получите исключение, а не перезапишете его правки.
Когда меняете несколько объектов, которые должны измениться вместе, оберните запись в транзакцию:
НачатьТранзакцию();
Попытка
Объект1.Записать();
Объект2.Записать();
ЗафиксироватьТранзакцию();
Исключение
ОтменитьТранзакцию();
ВызватьИсключение;
КонецПопытки;
Частые вопросы
Можно ли изменить реквизит без записи всего объекта?
Почему запросом нельзя присвоить значение реквизиту?
Как присвоить значение реквизиту сразу у многих элементов без программирования?
Чем `Константы.Имя.Установить()` отличается от менеджера значения?
Почему при записи документа значение реквизита перезаписывается другим?
ПередЗаписью или подписка на событие. Найдите код через глобальный поиск по имени реквизита в конфигураторе.