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