При разработке и доработке конфигураций на платформе 1С:Предприятие 7.7 разработчики нередко сталкиваются с ситуацией: при попытке прочитать значение реквизита справочника через стандартное обращение через точку система вместо ссылки или строки выводит сообщение НеизвестныйОбъект. При этом к другим реквизитам того же элемента доступ работает абсолютно корректно.
Разберем по шагам причину такого поведения платформы и рассмотрим правильные варианты чтения значений подобных реквизитов.
Проанализируем механику работы платформы 1С 7.7. Главная причина подобного поведения кроется в том, что реквизит в конфигураторе объявлен как периодический.
В отличие от обычных реквизитов, значения которых хранятся непосредственно в таблице справочника, периодические реквизиты хранят историю изменений в системной таблице 1SCONST. Если мы обращаемся к реквизиту напрямую (например, Товар.КлассификторАлк), платформа возвращает не само значение на текущий момент, а специальный внутренний агрегатный объект управления периодическим реквизитом. При попытке преобразовать такой объект в строку или передать в процедуру Сообщить() среда 1С 7.7 отображает системное строковое представление НеизвестныйОбъект.
Для чтения значения периодического реквизита платформе обязательно требуется контекст даты, на которую необходимо получить срез данных. Ниже рассмотрим основные способы решения задачи.
Выясним наиболее простой и распространенный способ. Если мы работаем с экземпляром объекта справочника, созданном через СоздатьОбъект("Справочник.Номенклатура"), перед чтением периодического реквизита необходимо явно задать дату выборки с помощью метода ИспользоватьДату().
Посмотрим на пример кода:
Товар = СоздатьОбъект("Справочник.Товары");
Если Товар.НайтиПоКоду("00001") = 1 Тогда
// Задаем дату, на которую платформа должна прочитать периодический реквизит
Товар.ИспользоватьДату(ТекущаяДата(), 1);
// Теперь обращение через точку вернет реальное значение справочника
Сообщить("Классификатор: " + Товар.КлассификторАлк);
КонецЕсли;
Обратите внимание на второй параметр метода: передача единицы 1 предписывает платформе учитывать позицию и движения документов за указанный день, если значение периодического реквизита менялось документами.
Рассмотрим альтернативный способ через специализированный объект платформы Периодический. Этот вариант незаменим, когда требуется не просто узнать значение на дату, но и определить документ-регистратор или конкретное время изменения реквизита.
Разберем пример работы с объектом:
Период = СоздатьОбъект("Периодический");
// Привязываем объект к периодическому реквизиту конкретного элемента
Период.ИспользоватьОбъект("КлассификторАлк", Товар.ТекущийЭлемент());
// Получаем значение на нужную дату
ЗначениеКлассификатора = Период.Получить(РабочаяДата());
Сообщить("Классификатор: " + ЗначениеКлассификатора);
// При необходимости можно выяснить, каким документом было установлено значение:
ДокУстановки = Период.ТекущийДокумент();
Если перед нами стоит задача обработать не один элемент, а большой массив товаров, последовательный вызов методов ИспользоватьДату() или использование объекта Периодический в цикле приведет к сильному падению производительности из-за множественных одиночных обращений к таблице 1SCONST.
В таких случаях рекомендуется использовать встроенный язык запросов 1С 7.7. Запрос автоматически рассчитывает периодические реквизиты на указанную дату среза:
Запрос = СоздатьОбъект("Запрос");
ТекстЗапроса =
"//{{ЗАПРОС(ПериодическиеРеквизиты)
|Период с ВыбДата по ВыбДата;
|ТекТовар = Справочник.Товары.ТекущийЭлемент;
|Классификатор = Справочник.Товары.КлассификторАлк;
|Группировка ТекТовар без групп;
|"//}}ЗАПРОС
;
Если Запрос.Выполнить(ТекстЗапроса) = 1 Тогда
Пока Запрос.Группировка(1) = 1 Цикл
Сообщить(Строка(Запрос.ТекТовар) + ": " + Запрос.Классификатор);
КонецЦикла;
КонецЕсли;
При разработке учитывайте следующие особенности платформы 1С 7.7:
ИспользоватьДату() устанавливает контекст только для того конкретного экземпляра переменной, для которого он был вызван. Если вы передадите ссылку на элемент в другую функцию и вызовете СоздатьОбъект() заново, дату потребуется устанавливать повторно.Товар.КлассификторАлк = НовоеЗначение; Товар.Записать();), предварительный вызов ИспользоватьДату() также обязателен, иначе запись завершится ошибкой времени выполнения.