Почему при переносе документов из 1С 7.7 по OLE возникает ошибка «Поле объекта не обнаружено (Сумма)» и как ее исправить?

Программист 1С v7.7 1C:Бухгалтерия IT и автоматизация бизнеса
← На главную

При организации интеграции или переноса данных из базы 1С:Предприятия 7.7 в конфигурации 1С:Предприятия 8 через COM-соединение (OLE Automation) разработчики нередко сталкиваются с непредвиденным поведением платформы. Типичная ситуация: документ успешно инициализирован, перебор строк табличной части выполняется штатно, большинство реквизитов считываются напрямую через точку, однако на конкретном реквизите (часто с именем Сумма) процесс прерывается критической ошибкой «Поле объекта не обнаружено».

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

Проанализируем типичный фрагмент кода в базе-приемнике 1С 8, где возникает данная проблема:


Док_КСФ = База77.CreateObject("Документ.КорректировочныйСчетФактура");
// ... позиционирование или выборка документов ...
Док_КСФ.ВыбратьСтроки();
Пока Док_КСФ.ПолучитьСтроку() = 1 Цикл
    стр = ДокР.Товары.Добавить();
    стр.Номенклатура = Справочники.Номенклатура.НайтиПоКоду(Док_КСФ.Наименование.Код).Ссылка;
    стр.Количество = Док_КСФ.Количество * Док_КСФ.Коэффициент;
    стр.КоличествоДоИзменения = Док_КСФ.КоличествоДоИзменения * Док_КСФ.Коэффициент;
    
    // На следующей строке генерируется исключение:
    стр.Сумма = Док_КСФ.Сумма; 
    
    стр.СтавкаНДС = ВернутьСтавкуНДС(Док_КСФ.СтавкаНДС);
КонецЦикла;

При этом визуально в конфигураторе 1С 7.7 реквизит табличной части существует, тип совпадает, а латинские буквы в имени отсутствуют. Выясним причину такого поведения OLE-сервера 1С 7.7.

Причины возникновения ошибки при обращении через COM

Посмотрим на внутреннее устройство взаимодействия двух платформ. Когда код 1С 8 обращается к свойству OLE-объекта через точку (Док_КСФ.Сумма), вызывается низкоуровневый интерфейс IDispatch::GetIDsOfNames. На стороне OLE-сервера 1С 7.7 возникает конфликт диспетчеризации по одной из следующих причин:

  1. Особенности динамического контекста табличной части. В 1С 7.7 реквизиты строк не являются статическими свойствами самого объекта документа. Они подставляются в контекст динамически только при установке курсора методом ПолучитьСтроку(). В ряде случаев механизм трансляции COM-запросов дает сбой при поиске динамических атрибутов.
  2. Конфликт с экспортными методами или переменными модуля. Если в модуле документа базы 7.7 объявлена экспортная процедура, функция или переменная с совпадающим именем (или системное совпадение сигнатур вызова), COM-сервер пытается вызвать метод вместо возврата значения реквизита. Не получив обязательных параметров, платформа выдает ошибку отсутствия поля.
  3. Включенный флаг «Итог по колонке» или одноименный реквизит шапки. Если в метаданных числовой колонки включен подсчет итога, платформа 7.7 формирует внутренний итог в шапке документа. При неявном разрешении контекста через COM возникает коллизия между итогом шапки и реквизитом текущей строки.

Способ 1. Использование встроенного метода ПолучитьАтрибут() (Основное решение)

Самый надежный и простой способ обойти сбой механизма диспетчеризации свойств — обратиться к прямому методу доступа к данным метаданных 1С 7.7. Метод ПолучитьАтрибут() обращается непосредственно к внутреннему контексту текущей строки документа, минуя неявные преобразования OLE-интерфейса.

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


Док_КСФ.ВыбратьСтроки();
Пока Док_КСФ.ПолучитьСтроку() = 1 Цикл
    стр = ДокР.Товары.Добавить();
    стр.Номенклатура = Справочники.Номенклатура.НайтиПоКоду(Док_КСФ.Наименование.Код).Ссылка;
    стр.Количество = Док_КСФ.Количество * Док_КСФ.Коэффициент;
    стр.КоличествоДоИзменения = Док_КСФ.КоличествоДоИзменения * Док_КСФ.Коэффициент;
    
    // Получение значения через встроенный метод метаданных:
    стр.Сумма = Док_КСФ.ПолучитьАтрибут("Сумма");
    
    стр.СтавкаНДС = ВернутьСтавкуНДС(Док_КСФ.ПолучитьАтрибут("СтавкаНДС"));
КонецЦикла;

Для записи значений в объекты базы 7.7 (если требуется обратная выгрузка) по аналогии следует использовать симметричный метод УстановитьАтрибут("ИмяРеквизита", Значение).

Способ 2. Выгрузка табличной части целиком в Таблицу Значений

Построчное чтение реквизитов документа через COM-соединение порождает огромное количество межпроцессных вызовов (RPC-маршалинг). Каждое обращение к свойству или методу отдельной строки выполняется крайне медленно. Если переносятся тысячи документов с большими табличными частями, эффективнее использовать штатную выгрузку всей табличной части в объект ТаблицаЗначений на стороне 7.7.

Рассмотрим, как реализовать этот подход:


// Создаем локальную для 7.7 таблицу значений
ТЗ_Семерка = База77.CreateObject("ТаблицаЗначений");

// Выгружаем табличную часть позиционированного документа
Док_КСФ.ВыгрузитьТабличнуюЧасть(ТЗ_Семерка);

// Обходим строки полученной таблицы значений
ТЗ_Семерка.ВыбратьСтроки();
Пока ТЗ_Семерка.ПолучитьСтроку() = 1 Цикл
    стр = ДокР.Товары.Добавить();
    стр.Количество = ТЗ_Семерка.ПолучитьЗначение(ТЗ_Семерка.НомерСтроки, "Количество");
    стр.Сумма = ТЗ_Семерка.ПолучитьЗначение(ТЗ_Семерка.НомерСтроки, "Сумма");
КонецЦикла;

Метод ВыгрузитьТабличнуюЧасть() переносит данные напрямую из физической структуры документа, полностью исключая возможные проблемы с позиционированием курсора и коллизиями свойств OLE-объекта.

Способ 3. Выполнение кода на стороне 7.7 через EvalExpr

Если требуется прочитать сложные реквизиты или предварительно обработать выборку данных, можно передать исполнение кода целиком во внутренний контекст 1С 7.7 с помощью метода EvalExpr(). Это позволяет проверить наличие реквизита функцией глЕстьРеквизитТабличнойЧасти или подготовить сериализованную структуру данных.

Посмотрим на пример вызова:


// Проверка наличия реквизита табличной части стандартными механизмами конфигурации 7.7:
ЕстьРеквизит = База77.EvalExpr("глЕстьРеквизитТабличнойЧасти(""Сумма"", ""КорректировочныйСчетФактура"")");
Если ЕстьРеквизит = 1 Тогда
    стр.Сумма = Док_КСФ.ПолучитьАтрибут("Сумма");
КонецЕсли;

Ограничения и важные нюансы работы с OLE-клиентом 1С 7.7

При разработке интеграций с «семеркой» необходимо помнить о системных особенностях платформы:

  1. Разрядность процесса: Платформа 1С 7.7 является исключительно 32-битным приложением. Вызов База77.CreateObject() или инициализация V77.Application завершится ошибкой, если код исполняется в 64-битном рабочем процессе сервера 1С 8. Фоновые задания и клиентские приложения 1С 8 для работы с 7.7 по COM должны запускаться в 32-разрядном режиме либо использовать суррогатный процесс Windows COM+ (dllhost.exe).
  2. Утечки памяти при больших объемах: OLE-сервер 1С 7.7 накапливает память при длительном переборе больших массивов документов. Рекомендуется обрабатывать документы пачками, периодически перезапуская OLE-соединение.
  3. Модальные окна: Любое исключение, предупреждение оператора (вызов Предупреждение()) или запрос подтверждения в коде 7.7 приведет к появлению невидимого модального окна и полной блокировке процесса переноса данных.
← На главную