В этой статье мы подробно разберем распространенную ошибку, возникающую у начинающих программистов 1С при работе с подчиненными справочниками. Часто при переносе логики из старых версий (7.7) или при недостаточном внимании к синтаксису возникает исключение при попытке программно найти элемент справочника.
Рассмотрим конкретную ситуацию: необходимо найти договор с наименованием "Основной договор", принадлежащий определенному контрагенту. Код, вызывающий ошибку, выглядит следующим образом:
Договор = Справочники.ДоговорыКонтрагентов.НайтиПоНаименованию("Основой договор", пко.Контрагент);
При выполнении этого кода система выдает ошибку:
Ошибка при вызове метода контекста (НайтиПоНаименованию): Несоответствие типов (параметр номер '2').
Давайте проанализируем причины и найдем правильное решение.
Чтобы понять суть проблемы, обратимся к синтаксису метода НайтиПоНаименованию. В платформе 1С:Предприятие 8 этот метод имеет строго определенный порядок параметров:
СправочникМенеджер.<Имя справочника>.НайтиПоНаименованию(<Наименование>, <ТочноеСоответствие>, <Родитель>, <Владелец>)
Разберем назначение каждого параметра по порядку:
Истина, ищется полное совпадение строки. Если Ложь — поиск по вхождению (начинается с...).Теперь посмотрим на ошибочный код:
// ОШИБКА:
.НайтиПоНаименованию("Основой договор", пко.Контрагент);
Мы видим, что вторым параметром передается ссылка на контрагента (пко.Контрагент). Однако система ожидает там значение типа Булево (Истина или Ложь). Именно поэтому возникает ошибка несоответствия типов.
Справочник ДоговорыКонтрагентов подчинен справочнику Контрагенты. Это означает, что контрагент является Владельцем договора, а не Родителем (родитель — это папка внутри договоров) и не флагом точности поиска.
Чтобы код заработал корректно, нам нужно передать контрагента в четвертый параметр. Третий параметр (Родитель) в данном случае нам не нужен, поэтому мы его пропускаем.
Скорректированный код будет выглядеть так:
// Правильный вызов:
// 1. Имя
// 2. Точное соответствие (Истина)
// 3. Родитель (пропускаем)
// 4. Владелец (наш контрагент)
Договор = Справочники.ДоговорыКонтрагентов.НайтиПоНаименованию("Основной договор", Истина, , пко.Контрагент);
Обратите внимание на две запятые подряд , , — это означает, что третий параметр оставлен пустым.
Хотя исправление синтаксиса решит техническую ошибку, профессиональный подход требует более глубокого анализа задачи. Поиск договора по наименованию (строке "Основной договор") считается ненадежной практикой ("моветоном") по нескольким причинам:
НайтиПоНаименованию вернет первый попавшийся, который может быть помечен на удаление.Во многих типовых конфигурациях (например, Управление Торговлей, Бухгалтерия) у самого справочника Контрагенты есть реквизит ОсновнойДоговор. Это ссылка на справочник договоров.
Правильнее будет сначала проверить этот реквизит:
// Пробуем взять договор, назначенный основным у контрагента
НайденныйДоговор = пко.Контрагент.ОсновнойДоговор;
Если НайденныйДоговор.Пустая() Тогда
// Если основного нет, тогда уже пробуем искать или создаем новый
// ... логика поиска ...
КонецЕсли;
Для массовых загрузок данных или сложной логики (когда нам нужен договор с определенной валютой и видом) лучше использовать Запрос. Это позволит исключить помеченные на удаление элементы и учесть дополнительные параметры.
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ ПЕРВЫЕ 1
| Договоры.Ссылка КАК Ссылка
|ИЗ
| Справочник.ДоговорыКонтрагентов КАК Договоры
|ГДЕ
| Договоры.Владелец = &Владелец
| И Договоры.Наименование ПОДОБНО &Наименование
| И НЕ Договоры.ПометкаУдаления
| И Договоры.ВидДоговора = &ВидДоговора";
Запрос.УстановитьПараметр("Владелец", пко.Контрагент);
Запрос.УстановитьПараметр("Наименование", "Основной%"); // Ищем начинающиеся на "Основной"
Запрос.УстановитьПараметр("ВидДоговора", Перечисления.ВидыДоговоровКонтрагентов.СПокупателем);
Результат = Запрос.Выполнить();
Если Не Результат.Пустой() Тогда
Выборка = Результат.Выбрать();
Выборка.Следующий();
Договор = Выборка.Ссылка;
Иначе
// Создаем новый договор
КонецЕсли;
Используя эти методы, вы не только избежите ошибок типов данных, но и сделаете ваш код устойчивым к изменениям данных в базе.