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

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

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

Разбираем причины: почему ссылки могут быть не равны?

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

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

Способ 1. Сравнение через уникальный идентификатор (GUID)

Как показало обсуждение, наиболее универсальным способом решения проблемы (особенно при работе с разными контекстами или внешними данными) является сравнение уникальных идентификаторов, приведенных к строковому типу. Рассмотрим пример кода, который позволяет обойти проблему несовпадения типов:


Для Каждого СтрВнеш Из ТаблицаВнешнихДанных Цикл
    Для Каждого СтрВнут Из ТаблицаВнутреннихДанных Цикл
        // Приводим идентификаторы к строке для гарантированного сравнения
        ИД_Внеш = Строка(СтрВнеш.Номенклатура.УникальныйИдентификатор());
        ИД_Внут = Строка(СтрВнут.Номенклатура.УникальныйИдентификатор());
        
        Если ИД_Внеш = ИД_Внут Тогда
            Сообщить("Номенклатура совпала: " + СтрВнеш.Номенклатура);
            // Ваша логика обработки
        КонецЕсли;
    КонецЦикла;
КонецЦикла;

Важный нюанс: метод УникальныйИдентификатор() доступен только у ссылок. Если в переменной может оказаться объект или неопределенное значение, необходимо добавить проверку типа или использовать функции метаданных.

Способ 2. Диагностика через проверку типов

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


Сообщить("Тип внешней номенклатуры: " + ТипЗнч(СтрСтараяТЗВнеш.Номенклатура));
Сообщить("Тип внутренней номенклатуры: " + ТипЗнч(СтрСтараяТЗВнут.Номенклатура));
Сообщить("Значение через XMLСтрока: " + XMLСтрока(СтрСтараяТЗВнеш.Номенклатура));

Использование XMLСтрока() — это отличная альтернатива преобразованию GUID в строку. Этот метод работает быстрее и часто используется для сериализации ссылок. Если значения XMLСтрока совпадают, значит, ссылки указывают на один и тот же объект базы данных.

Способ 3. Оптимизация через использование запросов

Сравнение таблиц в цикле (перебор "каждый с каждым") крайне неэффективно при больших объемах данных. Если вам нужно найти совпадения в двух таблицах значений, правильнее использовать временные таблицы в запросе. Запрос автоматически приведет типы к сопоставимому виду и выполнит сравнение на уровне СУБД, что в десятки раз быстрее.

Рассмотрим алгоритм действий:

  1. Выгружаем обе таблицы значений в менеджер временных таблиц.
  2. Описываем типы колонок для ТаблицаЗначений, чтобы система понимала, что сравниваются именно ссылки.
  3. Выполняем ВНУТРЕННЕЕ СОЕДИНЕНИЕ по полю Номенклатура.

МенеджерВТ = Новый МенеджерВременных Таблиц;

Запрос = Новый Запрос;
Запрос.МенеджерВременныхТаблиц = МенеджерВТ;
Запрос.Текст = "ВЫБРАТЬ * ПОМЕСТИТЬ ВТ_Данные ИЗ &ТЗ КАК ТЗ";
Запрос.УстановитьПараметр("ТЗ", ТаблицаНоменклатуры);
Запрос.Выполнить();

// Теперь в запросе можно легко сравнить данные из ВТ с другой таблицей или данными БД

Способ 4. Использование метода Свернуть()

Если ваша задача — "склеить" (суммировать) строки с одинаковой номенклатурой внутри одной таблицы значений, не нужно писать вложенные циклы со сравнениями. В 1С для этого предназначен встроенный высокопроизводительный метод Свернуть(). Проанализируем пример:


// Допустим, в ТЗ есть колонки Номенклатура, Количество, Сумма
// Мы хотим объединить дубли по номенклатуре
ТаблицаТоваров.Свернуть("Номенклатура", "Количество, Сумма");

Этот метод работает на уровне платформы и корректно обрабатывает ссылки одного типа, объединяя строки гораздо быстрее, чем любой ручной перебор с условиями Если ... Тогда.

Подводим итоги

Для корректного сравнения номенклатуры в 1С придерживайтесь следующих правил:

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

← На главную