Почему при сравнении элементов справочника в 1С возникает Ложь при одинаковых наименованиях

Программист 1С v8.3 (Управляемые формы) 1С:Управление торговлей IT и автоматизация бизнеса
← На главную

При разработке алгоритмов обработки данных в 1С начинающие разработчики часто сталкиваются с ситуацией, когда визуально одинаковые значения в отладчике при сравнении через оператор = возвращают значение Ложь. В результате приходится прибегать к приведению типов через Строка() и сравнению наименований, что является неоптимальным решением и приводит к ошибкам. Разберем по шагам причину такого поведения платформы 1С и рассмотрим правильные способы решения этой задачи.

Разбор причины: ссылки против строковых представлений

Проанализируем пример кода, в котором возникает проблема:


Если Выборка.Вид = Справочники.ВидыКонтактнойИнформации.НайтиПоНаименованию("Юридический адрес") Тогда
    КИКонтрагента.Вставить("ЮридическийАдрес", Выборка.Представление);    
ИначеЕсли Строка(Выборка.Вид) = Справочники.ВидыКонтактнойИнформации.НайтиПоНаименованию("Телефон").Наименование Тогда
    КИКонтрагента.Вставить("Телефон", Выборка.Представление);    
КонецЕсли;

Главная причина, почему первое условие возвращает Ложь, заключается в принципах работы ссылочного типа данных в 1С:

  1. Сравнение по уникальному идентификатору (GUID): Когда платформе передается выражение вида Ссылка1 = Ссылка2, она сравнивает не текст, который виден на экране, и не наименование элемента, а внутренние уникальные идентификаторы записей в базе данных. Если в базе существуют два элемента с одинаковым названием (например, "Юридический адрес" для контрагента и "Юридический адрес" для организации), это будут две совершенно разные ссылки.
  2. Дублирование элементов в иерархических справочниках: В типовых конфигурациях (включая Управление торговлей) справочник ВидыКонтактнойИнформации имеет иерархическую структуру. Элементы с наименованием "Телефон" или "Юридический адрес" существуют отдельно для справочников Контрагенты, Партнеры, Пользователи и Организации. Метод НайтиПоНаименованию() без указания родителя находит первую попавшуюся запись в базе, которая может не совпадать с той записью, которая находится в Выборка.Вид.
  3. Различие типов данных: Для проверки типов всегда следует использовать функцию ТипЗнч(). Если с одной стороны условия находится ссылка на объект (СправочникСсылка.ВидыКонтактнойИнформации), а с другой — строка или иной тип данных, результат сравнения всегда будет равен Ложь.

Почему сравнение через Строка() является антипаттерном

Приведение к строке Строка(Выборка.Вид) = ... решает проблему визуально, однако создаёт существенные риски для приложения:

  1. Падение производительности: Вызов метода НайтиПоНаименованию() внутри цикла или выборки выполняет отдельный SQL-запрос к базе данных на каждой итерации.
  2. Ненадежность логики: Пользователи с соответствующими правами могут легко переименовать элемент в режиме "1С:Предприятие", после чего жестко завязанный на строку код перестанет работать.

Правильные способы сопоставления видов контактной информации

Рассмотрим безопасные и производительные варианты написания кода.

Вариант 1. Использование предопределенных элементов

В конфигурациях на базе БСП основные виды контактной информации являются предопределенными. Правильнее всего выполнять сравнение напрямую с предопределенным значением:


Если Выборка.Вид = Справочники.ВидыКонтактнойИнформации.ЮрАдресКонтрагента Тогда
    КИКонтрагента.Вставить("ЮридическийАдрес", Выборка.Представление);
ИначеЕсли Выборка.Вид = Справочники.ВидыКонтактнойИнформации.ТелефонКонтрагента Тогда
    КИКонтрагента.Вставить("Телефон", Выборка.Представление);
КонецЕсли;

Также можно применять универсальную функцию платформы ПредопределенноеЗначение():


Если Выборка.Вид = ПредопределенноеЗначение("Справочник.ВидыКонтактнойИнформации.ЮрАдресКонтрагента") Тогда
    // Обработка
КонецЕсли;

Вариант 2. Точный поиск по родителю

Если элемент не является предопределенным и требуется найти его по наименованию, необходимо явно указывать группу-родителя при поиске, чтобы исключить получение ссылки из чужой папки:


ГруппаКонтрагенты = Справочники.ВидыКонтактнойИнформации.СправочникКонтрагенты;
ВидТелефон = Справочники.ВидыКонтактнойИнформации.НайтиПоНаименованию("Телефон", Истина, ГруппаКонтрагенты);

Если Выборка.Вид = ВидТелефон Тогда
    КИКонтрагента.Вставить("Телефон", Выборка.Представление);
КонецЕсли;

Вариант 3. Проверка типа контактной информации

Если задача заключается в том, чтобы сгруппировать данные по категориям (все телефоны или все адреса независимо от конкретного вида), следует проверять реквизит Тип:


Если Выборка.Вид.Тип = Перечисления.ТипыКонтактнойИнформации.Адрес Тогда
    // Действия для адреса
ИначеЕсли Выборка.Вид.Тип = Перечисления.ТипыКонтактнойИнформации.Телефон Тогда
    // Действия для телефона
КонецЕсли;

Вариант 4. Использование типового API подсистемы БСП

Для получения контактной информации объектов в современных конфигурациях рекомендуется использовать функции общего модуля УправлениеКонтактнойИнформацией, не выполняя ручной обход выборки:


СтруктураКИ = УправлениеКонтактнойИнформацией.КонтактнаяИнформацияОбъекта(СсылкаКонтрагента);

Выяснив причину разницы между представлением элемента и его ссылкой в базе данных, можно писать надежный код, устойчивый к переименованию элементов и пользовательским ошибкам.

← На главную