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