Особенности работы 1С+ADO+MSSQL и Oracle.

12.09.11

Интеграция - Внешние источники данных

В моей работе пришлось столкнуться с  задачей обмена данными XML через Шину (MDM), используя ADO. При построении такого обмена есть некоторые особенности, о которых я попытаюсь рассказать в данной статье.

Чтобы не нагружать данную статью, шиной будем считать некую таблицу на MSSQL (Oracle), в которую записываются пакеты обмена (XML) для определенной базы данных. Изначально шина была построена на MSSQL. Привожу пример записи пакета в шину для MSSQL:

Процедура СоздатьПараметрЗапроса(extCommSQL, названиеПараметр, текстПараметр)
    Для Инд = 0 по extCommSQL.Parameters.Count - 1 Цикл
        Если extCommSQL.Parameters.Item(Инд).Name = НазваниеПараметр тогда
            extCommSQL.Parameters.Item(Инд).Value = ТекстПараметр;
        КонецЕсли;
    КонецЦикла;
КонецПроцедуры

Функция ПолучитьСоединениеСБазой()
    extConnSQL = Новый ComОбъект("ADODB.Connection");
    СтрокаСоединения =  "Provider=SQLOLEDB.1;
    |User ID=user;
    |Pwd=pass;
    |Data Source=server;
    |Initial Catalog=Base";
    extConnSQL.ConnectionString = СтрокаСоединения;
    extConnSQL.Open();
    Возврат extConnSQL;
КонецФункции

Функция ЗаписьВSQL(ИмяБазыПолучателя,ИмяСправочника,УИД,ХМЛ, ОписаниеОшибки, Соединение=Неопределено)
    txtQuery="[gate1C].sp_Write";
    СоединениеСБазой = ?(Соединение = Неопределено, ПолучитьСоединениеСБазойSQL(), Соединение);
    ЗапросАДО=Новый COMОбъект("ADODB.Command");
    ЗапросАДО.ActiveConnection=СоединениеСБазой;
    ТекстЗапроса=txtQuery;
    ЗапросАДО.CommandText=ТекстЗапроса;
    ЗапросАДО.CommandType = 4;

    СоздатьПараметрЗапроса(ЗапросАДО, "@ReceiverSystemCode", ИмяБазыПолучателя);
    СоздатьПараметрЗапроса(ЗапросАДО, "@EntityType", ИмяСправочника);
    СоздатьПараметрЗапроса(ЗапросАДО, "@EntityID",УИД);
    СоздатьПараметрЗапроса(ЗапросАДО, "@XMLtext", ХМЛ);
    ЗапросАДО.Prepared = true;
    Попытка
        ЗапросАДО.Execute();
        Ошибка = Ложь;
    Исключение
        Ошибка = Истина;
        ОписаниеОшибки = ОписаниеОшибки();
    КонецПопытки;
    Если Соединение = Неопределено Тогда
        ЗакрытьСоединениеСБазой(СоединениеСБазой);
    КонецЕсли;
    Возврат не Ошибка;
КонецФункции

Понятно, что на сервере есть хранимая процедура (ЗапросАДО.CommandType = 4; 1- для запроса) [gate1C].sp_Write, с 4 параметрами, которая записывает данные в исходную таблицу. Здесь проблем нет, драйвер SQL OLEDB без проблем понимает и записывает большие пакеты. Пример функции чтения из шины для MSSQL:

Функция ЧтениеИзSQL(ИмяБазы)
    txtQuery="[gate1C].sp_GetAllUnLoaded";
    СоединениеСБазой=ПолучитьСоединениеСБазой();
    ЗапросАДО=Новый COMОбъект("ADODB.Command");
    ЗапросАДО.ActiveConnection=СоединениеСБазой;
    ТекстЗапроса=txtQuery;
    ЗапросАДО.CommandText=ТекстЗапроса;
    ЗапросАДО.CommandType = 4;
    СоздатьПараметрЗапроса(ЗапросАДО, "@ReceiverSystemCode", ИмяБазы);
    ЗапросАДО.Prepared = true;
    rsTABLE=ЗапросАДО.Execute();
    КоличествоПолейТаблица=rsTABLE.fields.Count-1;
    ТаблицаПоискаТаблица = Новый массив;
    Если (НЕ rsTABLE.EOF) Тогда
        ТаблицаПоискаТаблица = rsTABLE.GetRows().Выгрузить();
    КонецЕсли;

    тзРезультат = Новый ТаблицаЗначений;
    Для сч = 0 По КоличествоПолейТаблица Цикл
        тзРезультат.Колонки.Добавить(rsTABLE.fields.item(сч).name);
    КонецЦикла;

    Для Каждого стрТаблица Из ТаблицаПоискаТаблица Цикл
        стр=тзРезультат.Добавить();
        Для сч = 0 По КоличествоПолейТаблица Цикл
            попытка
                стр[сч] = СокрЛП(стрТаблица[сч]);
            исключение
                сообщить(ОписаниеОшибки());
            конецпопытки;
        КонецЦикла;
    КонецЦикла;
    ЗакрытьСоединениеСБазой(СоединениеСБазой);
    Возврат тзРезультат;
КонецФункции

Функция возвращает ТаблицуЗначений с результатами SELECT-а из шины. [gate1C].sp_GetAllUnLoaded также хранимая процедура. Вместо нее можно использовать обыкновенный SELECT, указав ЗапросАДО.CommandType = 1

При переводе шины на Oracle, столкнулся сразу с 2-умя сложностями. Для хранения пакетов XML в таблице Oracle использовался тип данных CLOB (Character large object). Т.к. ODBC драйвер для Oracle не поддерживает пакеты больше 32кб, использовал драйвер OraOLEDB, Функция соединения с базой приведена ниже:

Функция ПолучитьСоединениеСШинойДанных() Экспорт
    extConnSQL = Новый ComОбъект("ADODB.Connection");
    СтрокаСоединения =  "Provider=OraOLEDB.Oracle;Data Source=(DESCRIPTION=(CID=orcl)(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=oracle)(PORT=15)))(CONNECT_DATA=(SID=orcl)(SERVER=DEDICATED)));User Id=user;Password=pass;";
    extConnSQL.ConnectionString = СтрокаСоединения;
    extConnSQL.Open();
    Сообщить("Подключились к шине!");
    Возврат extConnSQL;
КонецФункции

Но и с этим драйвером оказалось не все гладко, т.к. на пакеты более 32 кб, также выдавалась ошибка. Проблема решалась установкой параметра

SPPrmsLOB = true;

Только после этого запись пакета стала производиться успешно. Код процедуры ниже:

Процедура СоздатьПараметрЗапросаСШинойДанных(extCommSQL, названиеПараметр, текстПараметр,Тип=205,Вид=1 )
    Параметр= extCommSQL.CreateParameter(названиеПараметр,Тип,Вид,СтрДлина(текстПараметр)+1,текстПараметр);
    extCommSQL.Parameters.append(Параметр);
КонецПроцедуры


Функция ЗаписьВШинуДанных(ИмяБазыПолучателя,ИмяСправочника,УИД,ХМЛ, ОписаниеОшибки, Соединение=Неопределено) Экспорт
    txtQuery="BUS_EXPORT.sendMessage";
    СоединениеСБазой = ?(Соединение = Неопределено, ПолучитьСоединениеСШинойДанных(), Соединение);
    ЗапросАДО=Новый COMОбъект("ADODB.Command");
    ЗапросАДО.ActiveConnection=СоединениеСБазой;
    ТекстЗапроса=txtQuery;
    ЗапросАДО.CommandText=ТекстЗапроса;
    ЗапросАДО.CommandType = 4;

    СоздатьПараметрЗапросаСШинойДанных(ЗапросАДО, "messageData"    , ХМЛ,202);
    СоздатьПараметрЗапросаСШинойДанных(ЗапросАДО, "messageObject"  , ИмяСправочника,12);
    СоздатьПараметрЗапросаСШинойДанных(ЗапросАДО, "messageDest"   СокрЛП(ИмяБазыПолучателя),12);
    СоздатьПараметрЗапросаСШинойДанных(ЗапросАДО, "messageID"      , УИД,12);
    ЗапросАДО.Prepared = true;
    ЗапросАДО.Properties("SPPrmsLOB").value=Истина;
    Попытка
        ЗапросАДО.Execute();
        Ошибка = Ложь;
    Исключение
        Ошибка = Истина;
        ОписаниеОшибки = ОписаниеОшибки();
    КонецПопытки;
    Если Соединение = Неопределено Тогда
        ЗакрытьСоединениеСШиной(СоединениеСБазой);
    КонецЕсли;
    Возврат не Ошибка;
КонецФункции

Для поля типа CLOB тип значения в CreateParameter - 202, для varchar2 -12

При чтении данных также не все просто, т.к. RecordSet хранимая процедура также возвращать не хотела, для возврата такого типа нужно устанавливать параметр

PLSQLRSet=Истина

Пример чтения из шины:

Функция ЧтениеИзШины(ИмяБазы) Экспорт
    txtQuery="BUS_IMPORT.getNextMessagebyType";
    СоединениеСБазой=ПолучитьСоединениеСШинойДанных();
    ЗапросАДО=Новый COMОбъект("ADODB.Command");
    ЗапросАДО.ActiveConnection=СоединениеСБазой;
    ТекстЗапроса=txtQuery;
    ЗапросАДО.CommandText=ТекстЗапроса;
    ЗапросАДО.CommandType = 4;
    Если ЗначениеЗаполнено(ИмяОбъекта) тогда
        ТипыПакетов=СокрЛп(ИмяОбъекта);
    иначе
        ТипыПакетов="ALL";
    КонецЕсли;
    СоздатьПараметрЗапросаСШинойДанных(ЗапросАДО, "MessageType", ТипыПакетов,12);
    ЗапросАДО.Prepared = true;
    ЗапросАДО.Properties("SPPrmsLOB").value=Истина;
    ЗапросАДО.Properties("PLSQLRSet").value=Истина;
    rsCursor=ЗапросАДО.Execute();

    КоличествоПолейТаблица=rsCursor.fields.Count-1;

    ТаблицаПоискаТаблица = Новый массив;
    Если (НЕ rsCursor.EOF) Тогда
        ТаблицаПоискаТаблица = rsCursor.GetRows().Выгрузить();
    КонецЕсли;

    тзРезультат = Новый ТаблицаЗначений;
    Для сч = 0 По КоличествоПолейТаблица Цикл
        тзРезультат.Колонки.Добавить(rsCursor.fields.item(сч).name);
    КонецЦикла;

    Для Каждого стрТаблица Из ТаблицаПоискаТаблица Цикл
        стр=тзРезультат.Добавить();
        Для сч = 0 По КоличествоПолейТаблица Цикл
            попытка
                стр[сч] = СокрЛП(стрТаблица[сч]);
            исключение
                сообщить(ОписаниеОшибки());
            конецпопытки;
        КонецЦикла;
    КонецЦикла;
    ЗапросАДО.Properties("SPPrmsLOB").value=False;
    ЗапросАДО.Properties("PLSQLRSet").value=False;
    ЗакрытьСоединениеСШинойДанных(СоединениеСБазой);
    Возврат тзРезультат;
КонецФункции

См. также

Перенос данных из Парус 8 в ЗГУ 3

Зарплата Внешние источники данных Бюджетный учет Платформа 1С v8.3 Сложные периодические расчеты 1С:Зарплата и кадры государственного учреждения 3 Государственные, бюджетные структуры Россия Бухгалтерский учет Бюджетный учет Платные (руб)

Обработка позволяет перенести кадровую информацию и данные по заработной плате, фактических удержаниях, НДФЛ, вычетах, страховых взносах из базы Парус 8 учреждений в конфигурацию 1С:Зарплата и кадры государственного учреждения ред. 3 (ЗГУ) и начать с ней работать с любого месяца года.

84000 руб.

19.08.2020    22459    19    1    

22

Перенос данных из Парус 10 в ЗГУ ред.3

Внешние источники данных Кадровый учет Файловый обмен (TXT, XML, DBF), FTP Обмен между базами 1C Платформа 1С v8.3 Сложные периодические расчеты 1С:Зарплата и кадры государственного учреждения 3 Государственные, бюджетные структуры Россия Бухгалтерский учет Бюджетный учет Платные (руб)

Обработка позволяет перенести кадровую информацию и данные по заработной плате, фактических удержаниях, НДФЛ, вычетах, страховых взносах из базы Парус 10 учреждений в конфигурацию 1С:Зарплата и кадры государственного учреждения ред. 3 (ЗГУ) и начать с ней работать с любого месяца года.

60000 руб.

05.10.2022    9217    9    8    

10

Перенос данных из Парус 7.хх в ЗГУ ред.3

Внешние источники данных Зарплата Бюджетный учет Платформа 1С v8.3 Сложные периодические расчеты 1С:Зарплата и кадры государственного учреждения 3 Государственные, бюджетные структуры Россия Бухгалтерский учет Бюджетный учет Платные (руб)

Обработка позволяет перенести кадровую информацию и данные по заработной плате, фактических удержаниях, НДФЛ, вычетах, страховых взносах из базы Парус 7.хх учреждений в конфигурацию 1С:Зарплата и кадры государственного учреждения ред. 3 (ЗГУ) и начать с ней работать с любого месяца года.

24000 руб.

24.04.2017    48712    96    163    

86

Перенос начальных остатков из Парус 7.71 в БГУ

Внешние источники данных Взаиморасчеты Учет ОС и НМА Логистика, склад и ТМЦ Бюджетный учет Платформа 1С v8.3 Бухгалтерский учет 1С:Бухгалтерия 2.0 1С:Бухгалтерия государственного учреждения Государственные, бюджетные структуры Россия Бюджетный учет Платные (руб)

Перенос словарей и начальных остатков из ПП Парус-Бухгалтерия Бюджет 7.71 в 1Сv8 БГУ2. Заполнение словарей и документов по вводу начальных остатков. Не требуется установка ПП Парус7. Возможна дозагрузка. Позволит автоматически и наиболее полно ввести данные в программу для начала работы. 

15600 руб.

08.12.2011    81578    128    123    

147

Перенос данных из Парус 10 (Торнадо) в ЗГУ ред.3 через Excel

Внешние источники данных Загрузка и выгрузка в Excel Зарплата Бюджетный учет Платформа 1С v8.3 Сложные периодические расчеты 1С:Зарплата и кадры государственного учреждения 3 Государственные, бюджетные структуры Россия Бухгалтерский учет Бюджетный учет Платные (руб)

Обработка позволяет перенести кадровую информацию и данные по заработной плате из Парус 10(Торнадо) учреждений через файлы Excel в конфигурацию 1С:Зарплата и кадры государственного учреждения ред. 3 (ЗГУ). В принципе, обработка может быть использована для загрузки из файлов Excel, полученных из любых информационных систем.

24000 руб.

16.11.2018    30006    20    31    

21

Загрузка спецификаций в УНФ из системы Базис-мебельщик

Производство готовой продукции (работ, услуг) Внешние источники данных Платформа 1С v8.3 1С:Управление нашей фирмой 1.6 Лесное и деревообрабатывающее хозяйство Россия Управленческий учет Платные (руб)

Обработка предназначена для загрузки файлов, выгруженных из системы Базис-мебельщик, в справочник "Спецификации" для последующих процессов учета и диспетчирования полуфабрикатов и изделий.

7200 руб.

24.06.2021    19133    52    50    

29
Комментарии
В избранное Подписаться на ответы Сортировка: Древо развёрнутое
Свернуть все
0. provova 80 13.09.11 15:30 Сейчас в теме
В моей работе пришлось столкнуться с задачей обмена данными XML через Шину (MDM), используя ADO. При построении такого обмена есть некоторые особенности, о которых я попытаюсь рассказать в данной статье.

Перейти к публикации

1. help1Ckr 13.09.11 21:24 Сейчас в теме
Было бы интересно, если о самой шине немного просветили темных людей)
2. romansun 193 13.09.11 22:08 Сейчас в теме
3. provova 80 13.09.11 22:29 Сейчас в теме
help1Ckr
В 2ух словах тут не опишешь. Эта тема отдельной статьи, как будет время расскажу подробнее.

romansun
Еще 2 голоса, и разукрашу. Права на скачивание еще не заработал.
4. romansun 193 13.09.11 23:38 Сейчас в теме
(3)
голосов автору! ))

provova пишет:
В 2ух словах тут не опишешь. Эта тема отдельной статьи, как будет время расскажу подробнее.


+1, тоже с удовольствием почитал бы
5. Gasdrubal 14.09.11 10:02 Сейчас в теме
Добрый день, не хватает кода и пояснений по всяким возможностям ADO и того, с чем это едят. Про шину - умолчу))
В целом, хочется конкретики, например, про Оракл - там не все просто с курсором. Т.е. ваш метод я дли Оракла и Для MSSQL работало?

А так все понравилось, плюсую!
6. provova 80 14.09.11 10:46 Сейчас в теме
Да как раз с курсором и были сложности то есть хранимая процедура( TYPE refcur IS REF CURSOR; в заголовке пакеджа):

type TTB_BUF_OUT IS TABLE OF TB_BUF_OUT%ROWTYPE index by BINARY_INTEGER;

procedure getNextMessagebyType (MessageType in varchar2,Cur out refcur)
is
-- buf_row TB_BUF_OUT%ROWTYPE;
array_t TTB_BUF_OUT;
begin


update TB_BUF_OUT
set TB_BUF_OUT.MSG_STATUS = 'FAILED'
where TB_BUF_OUT.MSG_STATUS = '4'
;


-- полуечние списка строк для курсора
IF trim(MessageType) = 'ALL' THEN
OPEN Cur FOR
select *
from
TB_BUF_OUT
where
TB_BUF_OUT.MSG_STATUS in ('READY','1','2','3','4')
and ROWNUM < 100
order by
TB_BUF_OUT.ID_ESB
; -- EO OPEN
ELSE
-- для указанной сущности:
OPEN Cur FOR
select *
from
TB_BUF_OUT
where
TB_BUF_OUT.MSG_STATUS in ('READY','1','2','3','4')
and TB_BUF_OUT.MSG_TYPE like(RTRIM(MessageType) + '%')
and ROWNUM < 100
order by TB_BUF_OUT.ID_ESB;
END IF;


FETCH Cur BULK COLLECT INTO array_t;
FOR i in array_t.FIRST .. array_t.LAST
LOOP
UPDATE TB_BUF_OUT
set TB_BUF_OUT.MSG_STATUS = case length(TB_BUF_OUT.MSG_STATUS)
when 1 then to_char(to_number(TB_BUF_OUT.MSG_STATUS) + 1)
else '1'
end
WHERE TB_BUF_OUT.ID = array_t(i).id;
END LOOP;

end;
То есть процедура возвращает курсор, и чтобы результат был в виде рекордсет устанавливается параметр
PLSQLRSet =Истина.
Я достаточно долго пробовал разными путями получить хоть какой то результат, но получилось только этим.
igor_L; Euroset1; +2 Ответить
7. hexus 3 21.09.11 12:40 Сейчас в теме
Спасибо за информацию, очень помогла разобраться с некоторыми моментами. Очень жду продолжения
Оставьте свое сообщение