При интеграции двух информационных баз 1С с помощью внешнего соединения (COM-соединения) часто возникает задача поиска конкретного документа и чтения строк его табличной части. При реализации этого сценария разработчики нередко сталкиваются с ситуацией, когда метод поиска возвращает пустую ссылку или запрос к табличной части не возвращает никаких записей. Разберем причины такого поведения и рассмотрим надежные способы решения этой задачи.
Проанализируем исходный код, в котором документ ищется методом менеджера документа:
СсылкаНаОбъект = Соединение.Документы.РеализацияТоваровУслуг.НайтиПоНомеру("01000000001");
Если в конфигурации для нумератора документов установлена периодичность (например, в пределах года), метод НайтиПоНомеру требует указания даты интервала. Выделим основные причины, из-за которых поиск документа дает пустой результат:
2014) нельзя — параметр ДатаИнтервала должен иметь строгий тип Дата.НайтиПоНомеру не вызывает исключений при отсутствии совпадений, а возвращает пустую ссылку. При передаче такой ссылки в параметры последующего запроса выборка гарантированно окажется пустой.Рассмотрим правильный синтаксис поиска документа, если мы хотим предварительно получить ссылку на объект во внешней базе. В метод НайтиПоНомеру обязательно передаем дату, входящую в нужный финансовый год:
// Формируем дату нужного периода
ДатаПоиска = Дата(2014, 1, 1);
// Ищем документ с явным указанием периода нумерации
СсылкаНаОбъект = Соединение.Документы.РеализацияТоваровУслуг.НайтиПоНомеру("01000000001", ДатаПоиска);
Если Не Соединение.ЗначениеЗаполнено(СсылкаНаОбъект) Тогда
Сообщить("Документ с указанным номером не найден в заданном периоде!");
Возврат;
КонецЕсли;
// Выполняем запрос к табличной части документа
Запрос = Соединение.NewObject("Запрос");
Запрос.Текст =
"ВЫБРАТЬ
| Товары.НомерСтроки КАК НомерСтроки,
| Товары.Номенклатура.Код КАК Код,
| Товары.Количество КАК Количество
|ИЗ
| Документ.РеализацияТоваровУслуг.Товары КАК Товары
|ГДЕ
| Товары.Ссылка = &Ссылка";
Запрос.УстановитьПараметр("Ссылка", СсылкаНаОбъект);
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
Сообщить("Строка: " + Выборка.НомерСтроки + " | Код: " + Выборка.Код + " | Количество: " + Выборка.Количество);
КонецЦикла;
Разберем по шагам наиболее производительный и правильный архитектурный подход. Выполнять отдельный вызов метода НайтиПоНомеру через COM-соединение избыточно, так как каждое обращение через границу процессов создает накладные расходы. Гораздо эффективнее объединить поиск документа и выборку данных табличной части в единый запрос во внешней базе.
Посмотрим на пример запроса, где условие по номеру и периоду накладывается непосредственно на реквизиты шапки документа через поле Ссылка:
Соединение = ПолучитьПодключениеКФайловойБД();
Если Соединение = Неопределено Тогда
Возврат;
КонецЕсли;
Запрос = Соединение.NewObject("Запрос");
Запрос.Текст =
"ВЫБРАТЬ
| Товары.НомерСтроки КАК НомерСтроки,
| Товары.Номенклатура.Код КАК Код,
| Товары.Количество КАК Количество
|ИЗ
| Документ.РеализацияТоваровУслуг.Товары КАК Товары
|ГДЕ
| Товары.Ссылка.Номер = &Номер
| И Товары.Ссылка.Дата МЕЖДУ &ДатаНачала И &ДатаОкончания";
Запрос.УстановитьПараметр("Номер", "01000000001");
Запрос.УстановитьПараметр("ДатаНачала", Дата(2014, 1, 1, 0, 0, 0));
Запрос.УстановитьПараметр("ДатаОкончания", Дата(2014, 12, 31, 23, 59, 59));
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
Сообщить("Строка: " + Выборка.НомерСтроки + ", Код: " + Выборка.Код + ", Количество: " + Выборка.Количество);
КонецЦикла;
Такой подход исключает промежуточные COM-вызовы, защищает от ошибок с неинициализированными ссылками и выполняется на стороне СУБД внешней базы за один шаг.
Выясним важные технические нюансы, о которых следует помнить при эксплуатации COMConnector:
comcntr.dll. Если 64-разрядный сервер 1С обращается к 32-разрядному коннектору, потребуется создание COM+ приложения в службах компонентов Windows.