Почему при COM-соединении метод Документы.НайтиПоНомеру возвращает пустую ссылку и как это исправить?

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

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

Причина 1. Периодическая нумерация документов и пропущенный параметр даты

Проанализируем механику работы метода НайтиПоНомеру() платформы 1С:Предприятие. Синтаксис метода принимает два параметра:

  1. НомерДокумента (обязательный) — строковый номер документа.
  2. Период (необязательный) — дата из периода, в котором выполняется поиск.

Если в конфигурации для конкретного вида документа включена периодичность нумерации (например, в пределах года, месяца или квартала), метод НайтиПоНомеру() без второго параметра ищет документ в периоде пустой даты — Дата(1, 1, 1) (0001 год). Так как реальные документы создаются в текущих периодах, метод предсказуемо возвращает пустую ссылку.

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


Пока ВыборкаДетальныеЗаписи.Следующий() Цикл
    // Обязательно передаем дату для документов с периодической нумерацией
    СсылкаВБазеПриемнике = Подключение.Документы.ПрочееОприходованиеТоваров.НайтиПоНомеру(ВыборкаДетальныеЗаписи.Номер, ВыборкаДетальныеЗаписи.Дата);
    
    Если СсылкаВБазеПриемнике.Пустая() Тогда
        Сообщить("Документ не найден: " + ВыборкаДетальныеЗаписи.Номер);
    КонецЕсли;
КонецЦикла;

Причина 2. Особенности строкового представления номера и разделители данных

Если передача даты не решила проблему, выясним сопутствующие причины, влияющие на результат поиска:

  1. Формат номера и лидирующие нули: метод НайтиПоНомеру() выполняет строгое строковое сопоставление. Если в одной базе номер хранится с префиксом или ведущими нулями (например, "0000-000123"), а в запросе передается усеченная строка (например, "123"), совпадение найдено не будет.
  2. Ограничения прав доступа (RLS): если пользователь COM-подключения ограничен правами на уровне записей, невидимые для него документы будут возвращаться как пустые ссылки без генерации исключений.
  3. Разделители данных в облачных базах: при работе с разделенными базами данных отсутствие указания области данных в строке подключения приводит к тому, что поиск выполняется в пустой или дефолтной области.

Способ 1. Синхронизация документов по уникальному идентификатору (УИД)

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

Разберем по шагам, как выполнить поиск по УИД и проверить факт существования документа:


Пока ВыборкаДетальныеЗаписи.Следующий() Цикл
    // Получаем строковое представление УИД из текущей базы
    СтрокаУИД = Строка(ВыборкаДетальныеЗаписи.Ссылка.УникальныйИдентификатор());
    
    // Создаем объект УИД в пространстве COM-подключения
    УИД_Приемник = Подключение.NewObject("УникальныйИдентификатор", СтрокаУИД);
    
    // Получаем ссылку в приемнике
    СсылкаВПриемнике = Подключение.Документы.ПрочееОприходованиеТоваров.ПолучитьСсылку(УИД_Приемник);
    
    // Метод ПолучитьСсылку() всегда возвращает ссылку (в том числе "битую").
    // Для проверки реального существования записи получаем объект:
    ОбъектДокумента = СсылкаВПриемнике.ПолучитьОбъект();
    
    Если ОбъектДокумента = Неопределено Тогда
        Сообщить("Документ отсутствует в базе-приемнике: " + ВыборкаДетальныеЗаписи.Ссылка.Номер);
    Иначе
        // Документ существует в базе-приемнике
    КонецЕсли;
КонецЦикла;

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

Рассмотрим важный аспект производительности. Вызов методов COM-объекта внутри цикла (особенно ПолучитьОбъект(), который считывает из базы всю шапку и табличные части) порождает огромное количество межпроцессных вызовов (COM Marshaling) и сильно замедляет работу.

Для ускорения обработки сотен и тысяч документов оптимально выгрузить массив номеров или идентификаторов и выполнить один пакетный запрос на стороне базы-приемника:


// 1. Формируем массив номеров в текущей базе
МассивНомеров = Новый Массив;
Пока ВыборкаДетальныеЗаписи.Следующий() Цикл
    МассивНомеров.Добавить(ВыборкаДетальныеЗаписи.Номер);
КонецЦикла;

// 2. Создаем и выполняем запрос в COM-базе
ЗапросВПриемнике = Подключение.NewObject("Запрос");
ЗапросВПриемнике.Текст = 
    "ВЫБРАТЬ
    |    Док.Номер КАК Номер
    |ИЗ
    |    Документ.ПрочееОприходованиеТоваров КАК Док
    |ГДЕ
    |    Док.Номер В (&МассивНомеров)";

// Передаем параметры через СОМ-массив или строковый список
ЗапросВПриемнике.УстановитьПараметр("МассивНомеров", Подключение.NewObject("Массив"));
Для Каждого Номер Из МассивНомеров Цикл
    ЗапросВПриемнике.Параметры.МассивНомеров.Добавить(Номер);
КонецЦикла;

ТаблицаСуществующих = ЗапросВПриемнике.Выполнить().Выгрузить();
// Далее быстро сопоставляем данные в локальной памяти без лишних COM-обращений

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

← На главную