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