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