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