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