При организации интеграции и обмена данными между двумя базами 1С через COM-соединение разработчики часто сталкиваются с ситуацией, когда метод НайтиПоНомеру() возвращает пустую ссылку даже для тех документов, которые заведомо существуют в информационной базе-приемнике. Разберем детально, почему так происходит, какие скрытые нюансы несет в себе поиск по номеру, и рассмотрим проверенные способы корректного сопоставления объектов.
Проанализируем механику работы метода НайтиПоНомеру() платформы 1С:Предприятие. Синтаксис метода принимает два параметра:
Если в конфигурации для конкретного вида документа включена периодичность нумерации (например, в пределах года, месяца или квартала), метод НайтиПоНомеру() без второго параметра ищет документ в периоде пустой даты — Дата(1, 1, 1) (0001 год). Так как реальные документы создаются в текущих периодах, метод предсказуемо возвращает пустую ссылку.
Посмотрим на пример правильного вызова метода с передачей даты документа из выборки:
Пока ВыборкаДетальныеЗаписи.Следующий() Цикл
// Обязательно передаем дату для документов с периодической нумерацией
СсылкаВБазеПриемнике = Подключение.Документы.ПрочееОприходованиеТоваров.НайтиПоНомеру(ВыборкаДетальныеЗаписи.Номер, ВыборкаДетальныеЗаписи.Дата);
Если СсылкаВБазеПриемнике.Пустая() Тогда
Сообщить("Документ не найден: " + ВыборкаДетальныеЗаписи.Номер);
КонецЕсли;
КонецЦикла;
Если передача даты не решила проблему, выясним сопутствующие причины, влияющие на результат поиска:
НайтиПоНомеру() выполняет строгое строковое сопоставление. Если в одной базе номер хранится с префиксом или ведущими нулями (например, "0000-000123"), а в запросе передается усеченная строка (например, "123"), совпадение найдено не будет.Если базы данных являются копиями или синхронизируются с сохранением ссылочной целостности, наиболее надежным способом сопоставления является поиск по УникальныйИдентификатор. В COM-соединении нельзя напрямую передать локальный объект идентификатора, поэтому мы создаем объект типа УникальныйИдентификатор на стороне внешней базы из строкового представления.
Разберем по шагам, как выполнить поиск по УИД и проверить факт существования документа:
Пока ВыборкаДетальныеЗаписи.Следующий() Цикл
// Получаем строковое представление УИД из текущей базы
СтрокаУИД = Строка(ВыборкаДетальныеЗаписи.Ссылка.УникальныйИдентификатор());
// Создаем объект УИД в пространстве COM-подключения
УИД_Приемник = Подключение.NewObject("УникальныйИдентификатор", СтрокаУИД);
// Получаем ссылку в приемнике
СсылкаВПриемнике = Подключение.Документы.ПрочееОприходованиеТоваров.ПолучитьСсылку(УИД_Приемник);
// Метод ПолучитьСсылку() всегда возвращает ссылку (в том числе "битую").
// Для проверки реального существования записи получаем объект:
ОбъектДокумента = СсылкаВПриемнике.ПолучитьОбъект();
Если ОбъектДокумента = Неопределено Тогда
Сообщить("Документ отсутствует в базе-приемнике: " + ВыборкаДетальныеЗаписи.Ссылка.Номер);
Иначе
// Документ существует в базе-приемнике
КонецЕсли;
КонецЦикла;
Рассмотрим важный аспект производительности. Вызов методов COM-объекта внутри цикла (особенно ПолучитьОбъект(), который считывает из базы всю шапку и табличные части) порождает огромное количество межпроцессных вызовов (COM Marshaling) и сильно замедляет работу.
Для ускорения обработки сотен и тысяч документов оптимально выгрузить массив номеров или идентификаторов и выполнить один пакетный запрос на стороне базы-приемника:
// 1. Формируем массив номеров в текущей базе
МассивНомеров = Новый Массив;
Пока ВыборкаДетальныеЗаписи.Следующий() Цикл
МассивНомеров.Добавить(ВыборкаДетальныеЗаписи.Номер);
КонецЦикла;
// 2. Создаем и выполняем запрос в COM-базе
ЗапросВПриемнике = Подключение.NewObject("Запрос");
ЗапросВПриемнике.Текст =
"ВЫБРАТЬ
| Док.Номер КАК Номер
|ИЗ
| Документ.ПрочееОприходованиеТоваров КАК Док
|ГДЕ
| Док.Номер В (&МассивНомеров)";
// Передаем параметры через СОМ-массив или строковый список
ЗапросВПриемнике.УстановитьПараметр("МассивНомеров", Подключение.NewObject("Массив"));
Для Каждого Номер Из МассивНомеров Цикл
ЗапросВПриемнике.Параметры.МассивНомеров.Добавить(Номер);
КонецЦикла;
ТаблицаСуществующих = ЗапросВПриемнике.Выполнить().Выгрузить();
// Далее быстро сопоставляем данные в локальной памяти без лишних COM-обращений
Такой подход позволяет сократить время синхронизации в десятки раз и исключает возникновение ошибок, связанных с неполной передачей параметров при поиске по номеру.