Перейти к основному содержимому

Механизм обмена данными

Механизмы обмена данными — это набор средств, предназначенных для организации обмена данными между «Шиной» и:

  • другими приложениями «1С:Шины»;
  • информационными базами «1С:Предприятия»;
  • иными внешними информационными системами.

Центром механизма обмена данными являются планы обмена. В одном проекте можно определить произвольное количество планов обмена. Элементами данных плана обмена являются узлы плана обмена, подобно тому как элементами данных справочника являются элементы справочника. Каждый из узлов плана обмена обозначает участника обмена данными по данному плану обмена. Один из узлов соответствует данной информационной базе, а остальные — другим участникам, с которыми данная информационная база может обмениваться данными:

В планах обмена можно выделить три значимые составляющие:

Для реализации механизма обмена изменениями в «1С:Шине» предназначен элемент проекта ПланОбмена. Данный элемент позволяет описать:

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

Приложения, которые обмениваются изменениями данных, называются узлами плана обмена. Узлы добавляются администратором в конкретном приложении аналогично добавлению элементов справочника.

Состав плана обмена (элементы проекта, в которых регистрируются изменения данных) распространяется на все узлы данного плана обмена. Если с разными узлами нужно обмениваться разным составом информации, то необходимо создавать несколько планов обмена, в которых следует объединить узлы, обменивающиеся одинаковым составом информации.

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

Инфраструктура сообщений

Данные переносятся с помощью сообщений. Сообщения передаются в рамках плана обмена от одного узла другому. Средства работы с сообщениями образуют инфраструктуру сообщений. Каждое сообщение:

  • относится к определенному плану обмена;
  • имеет определенный узел-отправитель и определенный узел-получатель.

Сообщение нельзя отправить неизвестному узлу и принять от неизвестного узла. Каждое сообщение имеет свой собственный целочисленный номер. С точки зрения инфраструктуры сообщений у узла существуют два свойства:

  • номер отправленного сообщения,
  • номер принятого сообщения.

Для узла, соответствующего текущему приложению, эти свойства смысла не имеют (база данных сама с собой данными не обменивается).

Важнейшей составляющей инфраструктуры сообщений являются сами сообщения. Сообщение оформляется как документ XML, имеющий определенную структуру. В качестве примера рассмотрим следующее сообщение:

<v8msg:Message xmlns:v8msg="http://v8.1c.ru/messages">
<v8msg:Header>
<v8msg:ExchangePlan>УдаленныеСклады</v8msg:ExchangePlan>
<v8msg:To>Оптовый</v8msg:To>
<v8msg:From>ЦентрОфис</v8msg:From>
<v8msg:MessageNo>20</v8msg:MessageNo>
<v8msg:ReceivedNo>15</v8msg:ReceivedNo>
</v8msg:Header>
<v8msg:Body>
<!— Тело сообщения -->
</v8msg:Body>
</v8msg:Message>

Все сообщение находится внутри элемента XML с именем Message, относящимся к пространству имен http://v8.1c.ru/messages. Сообщение состоит из:

  • заголовка — Header;
  • тела сообщения — Body.

Они также относятся к пространству имен http://v8.1c.ru/messages.

Структура заголовка жестко задана. Информация заголовка представлена в нескольких элементах XML, вложенных в элемент Header. Все элементы, вложенные в элемент Header, относятся к пространству имен http://v8.1c.ru/messages.

  • Элемент с именем ExchangePlan содержит имя плана обмена, к которому относится сообщение. Имена планов обмена должны совпадать в системах, взаимодействующих через планы обмена.
  • Элемент с именем From содержит код узла-отправителя.
  • Элемент с именем To содержит код узла-получателя.
  • Элемент с именем MessageNo содержит номер данного сообщения. Номер сообщения является положительным целым числом и присваивается узлом-отправителем. Номер каждого последующего сообщения равен номеру предыдущего отправленного сообщения плюс 1.
  • Элемент с именем ReceivedNo содержит максимальный номер сообщения, которое узел-отправитель данного сообщения принял от узла-получателя данного сообщения. Данное значение включено в состав заголовка сообщения для подтверждения приема сообщений.

Тело сообщения содержится в элементе XML с именем Body, относящимся к пространству имен http://v8.1c.ru/messages. Данный элемент может иметь произвольное содержимое, определяемое прикладными потребностями. Инфраструктурой сообщений содержимое тела сообщения никак не регламентируется.

дополнительно

Если вы настраиваете обмен данными с информационными базами «1С:Предприятия», при формировании тела сообщения важно придерживаться формата XML-сериализации, который используется в механизмах обмена данными «1С:Предприятия».

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

метод ЗаписатьСообщениеОбмена(КодУзлаПолучателя : Строка, ИмяФайла : Строка)
пер Узел = УдаленныеСклады.НайтиПоКоду(КодУзлаПолучателя)


пер ФайлСообщенияОбмена = новый Файл(ИмяФайла)
пер ЗаписьXml = новый ЗаписьXml(ФайлСообщенияОбмена.ОткрытьПотокЗаписи())
исп ОбработкаИсходящегоСообщения = УдаленныеСклады.СоздатьОбработкуИсходящегоСообщения(ЗаписьXml, Узел)

// Заполнение тела сообщения
для Данные из УдаленныеСклады.ВыбратьИзмененияВСообщение(Узел, НомерСообщения)
// Запись данных, делает разработчик проекта
ЗаписатьДанныеВСообщениеОбмена(ОбработкаИсходящегоСообщения, Данные)
;
;

В результате вызова метода СоздатьОбработкуИсходящегоСообщения() создается объект типа ОбработкаИсходящегоСообщенияОбмена, с помощью которого может быть произведена запись одного или нескольких сообщений обмена данными, а также начинается запись этих сообщений. В качестве первого параметра метода передается объект типа ЗаписьXML, в качестве второго — ссылка на узел-получатель плана обмена.

При обращении к методу сообщению присваивается номер, определяемый как номер предыдущего отправленного сообщения, увеличенный на 1. Далее производится запись в XML заголовка сообщения, а также записывается начало элемента XML, соответствующего телу сообщения. В начале записи сообщения устанавливается блокировка на запись базы данных, соответствующую узлу плана обмена, чтобы предотвратить на время записи сообщения другие операции чтения и записи сообщений, относящихся к данному узлу, а также не допустить изменения данных узла. Сообщение считается отправленным только тогда, когда будет произведено обращение к методу Завершить().

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

Метод ЗаписатьДанныеВСообщениеОбмена() разработчику следует определить самостоятельно.

Завершить запись сообщения можно с помощью трех методов объекта ОбработкаИсходящегоСообщенияОбмена:

  • Завершить()

    Осуществляет нормальное завершение записи сообщения. При нормальном завершении в сообщение записывается конец элемента XML, представляющего тело сообщения, а в запись узла плана обмена записывается номер сообщения обмена данными. Блокировка с записи узла плана обмена снимается, и сообщение считается отправленным.

  • Отменить()

    Прерывает запись сообщения. Сообщение при этом считается неотправленным. Запись сообщения обмена может быть завершена либо обращением к методу Завершить(), либо обращением к методу Отменить().

  • Закрыть() (вызывается автоматически при выходе из области видимости)

    Выполняется метод Отменить(), если закрытие произошло из-за выброса исключения. В ином случае выполняется метод Завершить().

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

метод ПрочитатьXmlСообщениеОбмена(Отправитель: Склады.Ссылка, ПотокФайла: ПотокЧтения)
знч ЧтениеXml = новый ЧтениеXml(ПотокФайла)
исп ГрупповаяОперация.Начать(РежимЗагрузкиДанных = Истина)
исп ОбработкаВходящегоСообщенияОбмена = Склады.СоздатьОбработкуВходящегоСообщения(
ЧтениеXml,
ДопустимыйНомерСообщенияОбмена.Больший
)
знч ОтправительСсылка = ОбработкаВходящегоСообщенияОбмена.Отправитель как Склады.Ссылка
если ОтправительСсылка != Отправитель
выбросить новый ИсключениеНедопустимоеСостояние("Отправитель в сообщении отличается от отправителя каталога")
;
Склады.УдалитьРегистрациюИзмененийПоСообщению(ОтправительСсылка, ОбработкаВходящегоСообщенияОбмена.НомерПринятого)
пока ЧтениеXml.ВидУзла == ВидУзлаXml.НачалоЭлемента
ПрочитатьИзменениеДанных(ЧтениеXml, ОтправительСсылка)
;
;

При вызове метода СоздатьОбработкуВходящегоСообщения(ЧтениеXml) создается объект ОбработкаВходящегоСообщенияОбмена, с помощью которого может быть произведено чтение одного или нескольких сообщений обмена данными. При этом производится чтение заголовка сообщения обмена данными и проверяются содержащиеся в заголовке данные. Если какие-либо данные указаны неправильно (задан неизвестный план обмена, указан узел, не входящий в план обмена, номер сообщения не соответствует ожидаемому), вызывается исключение. В начале чтения сообщения устанавливается блокировка на запись базы данных, соответствующую узлу плана обмена, чтобы предотвратить на время чтения сообщения другие операции чтения и записи сообщений, относящихся к данному узлу, а также не допустить изменения данных узла.

Используя второй параметр ДопустимыйНомерСообщенияОбмена, можно установить вариант ожидаемого номера сообщения:

  • любой (фактически контроль номеров сообщения не производится);
  • больший (любой номер, больший чем максимальный номер принятого сообщения);
  • следующий (строго больший на единицу, чем предыдущий).

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

Завершить чтение сообщения можно с использованием трех методов:

  • Завершить()

    Вызывает попытку нормального завершения чтения сообщения. При этом проверяется нормальное завершение сообщения. Если обнаружен конец элемента XML, соответствующего телу сообщения, то в случае превышения номером сообщения максимального номера принятого сообщения он помещается в реквизит НомерПринятого узла плана обмена. Блокировка записи узла плана обмена снимается, и сообщение считается принятым.

  • Отменить()

    Вызывает немедленное прерывание чтения сообщения. Блокировка с записи базы данных, соответствующей узлу плана обмена, снимается, и в нее не вносится никаких изменений.

  • Закрыть() (вызывается автоматически при выходе из области видимости)

    Выполняется метод Отменить(), если закрытие произошло из-за выброса исключения. В ином случае выполняется метод Завершить().

При вызове метода УдалитьРегистрациюИзмененийПоСообщению() из таблиц регистрации изменений элементов проекта удаляются регистрации изменений, относящиеся к указанному узлу, с номером сообщения меньшим или равным значению переданного номера сообщения.

Метод ПрочитатьИзмененияИзСообщенияОбмена() разработчику следует определить самостоятельно.

Выгрузка и загрузка сообщений

«1С:Шина» предоставляет возможность обрабатывать тела сообщений при обмене данными. Формат XML, используемый для чтения/записи данных, зависит от свойства СхемаДанных плана обмена:

  • Свойство имеет значение Проект1СПредприятияЭлемент (значение по умолчанию)

    Обмен выполняется между приложениями «1С:Шины» в формате XML, который используется для сериализации данных объектов, порождаемых элементами проекта «1С:Шины».

  • Свойство имеет значение Конфигурация1СПредприятия8

    Обмен выполняется между приложением «1С:Шины» и информационной базой «1С:Предприятия» в формате XML, который используется механизмом обмена данными «1С:Предприятия» (пример).

Для выгрузки и загрузки данных поддерживаются следующие методы:

Ниже показано, как полностью выгрузить данные в сообщение обмена и загрузить их из сообщения на примере плана обмена Склады:

метод ВыгрузитьСообщениеОбмена(КодУзлаПолучателя: Строка, ИмяФайла: Строка)
пер Узел = УдаленныеСклады.НайтиПоКоду(КодУзлаПолучателя)
пер ФайлСообщенияОбмена = новый Файл(ИмяФайла)
пер ЗаписьСодержимого = новый ЗаписьXml(ФайлСообщенияОбмена.ОткрытьПотокЗаписи())
Склады.ВыгрузитьСообщение(ЗаписьСодержимого, Узел)
;

метод ЗагрузитьСообщениеОбмена(ИмяФайла: Строка)
пер ФайлСообщенияОбмена = новый Файл(ИмяФайла)
пер ЧтениеСодержимого = новый ЧтениеXml(ФайлСообщенияОбмена.ОткрытьПотокЧтения())
Склады.ЗагрузитьСообщение(ЧтениеСодержимого)
;

При необходимости вы можете внести изменения в процесс загрузки и выгрузки данных. Для этого используйте переопределяемые обработчики типа ПланОбмена.Объект:

  • ПриВыгрузкеДанных(Параметры: ПараметрыВыгрузкиОбменаДанными) — вызывается при выгрузке данных. Свойства объекта ПараметрыВыгрузкиОбменаДанными позволяют вам переопределить поведение по умолчанию.
  • ПриЗагрузкеДанных(Параметры: ПараметрыЗагрузкиОбменаДанными) — вызывается при загрузке данных. Свойства объекта ПараметрыЗагрузкиОбменаДанными позволяют вам переопределить поведение по умолчанию.

Рассмотрим использование данных обработчиков на примере документа РасходнаяНакладная. Пусть у данного документа имеется реквизит Склад типа Склады.Ссылка. Обмен данными организован в соответствии с планом обмена Склады. У данного плана обмена также определен реквизит Склад типа Склады.Ссылка. В соответствии с этим планом обмена организована распределенная информационная база, в которой корневым узлом является центральный офис, а его подчиненными узлами — склады. У каждого из подчиненных узлов плана обмена значение реквизита Склад обозначает, какому складу соответствует этот узел. Все документы РасходнаяНакладная должны присутствовать в корневом узле и попадать в подчиненные узлы только при совпадении значений реквизитов Склад в документе и узле плана обмена.

Чтобы документы РасходнаяНакладная попадали в нужные подчиненные узлы, обработчик события ПриВыгрузкеДанных должен иметь следующий вид:

@Обработчик
метод ПриВыгрузкеДанных(Параметры: ПараметрыВыгрузкиОбменаДанными)
если Параметры.Данные это РасходнаяНакладная.Объект
знч РасходнаяНакладная = Параметры.Данные как РасходнаяНакладная.Объект
если РасходнаяНакладная.Склад != Склад
Параметры.ВыгрузкаДанных = ДействиеПриВыгрузкеОбменаДанными.Удалить
;
;
;

В приведенном примере анализируется тип выгружаемых данных, и если он равен РасходнаяНакладная.Объект, то значение реквизита Склад документа сравнивается со значением реквизита Склад узла плана обмена. Если значения реквизитов равны, то в сообщение помещается XML-представление документа. Если же значения реквизитов не равны, то в сообщение помещается XML-представление объекта УдалениеОбъекта, проинициализированного ссылкой на соответствующий документ РасходнаяНакладная.

Если значение реквизита Склад документа РасходнаяНакладная может быть изменено в подчиненном узле, то в плане обмена необходимо определить обработчик события ПриЗагрузкеДанных следующего вида:

@Обработчик
метод ПриЗагрузкеДанных(Параметры: ПараметрыЗагрузкиОбменаДанными)
если Параметры.Данные это РасходнаяНакладная.Объект
знч РасходнаяНакладная = Параметры.Данные как РасходнаяНакладная.Объект
если РасходнаяНакладная.Склад != Склад
Параметры.ОтправлятьНазад = Истина
;
;
;

В приведенном примере анализируется тип загружаемых данных, и если он равен РасходнаяНакладная.Объект, то значение реквизита Склад документа сравнивается со значением реквизита Склад узла плана обмена. Если значения реквизитов не равны, параметру ОтправлятьНазад присваивается значение Истина. Тем самым гарантируется, что изменения документа будут зарегистрированы и при отправке сообщения подчиненному узлу будет отправлен объект УдалениеОбъекта, если, конечно, реквизит Склад документа не будет изменен в главном узле так, что он окажется равен значению реквизита Склад соответствующего узла плана обмена.

Служба регистрации изменений

Служба регистрации изменений предназначена для регистрации изменений данных, производимых «Шиной», чтобы при обмене данными иметь возможность передавать не все данные, а только новые, измененные или удаленные. Эти элементы данных должны быть переданы в очередном сообщении тому или иному узлу, с которым производится обмен данными. При каждом изменении данных должно быть зарегистрировано, что имеются изменения и их предстоит передать во все узлы, с которыми поддерживается обмен этими данными. При получении подтверждения приема сообщения, в котором были отправлены изменения, записи регистрации изменений должны быть удалены.

При определении состава элементов проекта, для которых производится регистрация изменений (свойство плана обмена Состав), для каждого элемента можно определить свойство АвтоРегистрация. Авторегистрацию можно разрешить или запретить. Если авторегистрация разрешена, то при изменении данных регистрация будет выполнена автоматически. Если запрещена, то регистрацию изменения необходимо выполнять «вручную» (определив код на встроенном языке). Следует отметить, что можно «корректировать» результат регистрации даже в том случае, когда авторегистрация элемента включена.

Регистрация изменений может выполняться для следующих элементов проекта:

Для каждого из приведенных элементов проекта ведется своя таблица регистрации изменений. Таблицы имеют разную структуру в зависимости от того, для каких элементов данных регистрируются изменения, однако структуры таблиц подобны. В структуре можно выделить три составляющих:

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

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

Подтверждение приема сообщений

При использовании плана обмена осуществляется подтверждение приема-передачи сообщений. Эта функциональность реализуется благодаря тому, что заголовок сообщения, как было сказано ранее, содержит два обязательных элемента:

  • Элемент с именем MessageNo, который содержит номер данного сообщения.
  • Элемент с именем ReceivedNo, который содержит максимальный номер сообщения, которое узел-отправитель данного сообщения принял от узла-получателя данного сообщения. Данное значение включено в состав заголовка сообщения для подтверждения приема сообщений.

Структура элемента проекта ПланОбмена подобна справочнику, где элементами являются узлы плана обмена. Для каждого узла существует четыре обязательных реквизита:

  • Код — код узла обмена, который используется для идентификации узла в другом узле обмена.
  • Номер отправленного — номер последнего сообщения, которое было отправлено в соответствующий узел обмена (MessageNo).
  • Номер принятого — номер последнего сообщения, которое было принято соответствующим узлом обмена (ReceivedNo).
  • Этот узел — узел, соответствующий данному приложению. Соответственно, для данного узла значения полей Номер отправленного и Номер принятого всегда равняются нулю.

Кроме того, существует один стандартный, однако необязательный реквизит:

  • Наименование — наименование узла обмена.

Рассмотрим на примере, каким образом реализуется подтверждение приема сообщений. Есть два приложения: «Офис» и «Склад», которые обмениваются изменениями данных в рамках плана обмена Склады:

  1. «Офис» отправляет сообщение на «Склад» с номером 1. В этот момент в заголовок сообщения, помимо прочих, будут записаны следующие значения:

    • MessageNo: 1 — номер сообщения, которое «Офис» отправляет на «Склад»;

    • ReceivedNo: 0 — информации о том, что «Склад» принял какое-либо сообщение, пока нет. В приложении «Офис», в плане обмена для узла «Склад», изменится значение поля:

    • Номер отправленного: 01

  2. «Склад» принимает сообщение от приложения «Офис» с номером 1. Далее «Склад» отправляет сообщение в «Офис» с номером 1. В этот момент в заголовок сообщения, помимо прочих, будут записаны следующие значения:

    • MessageNo: 1 — номер сообщения, которое «Склад» отправляет в «Офис»;

    • ReceivedNo: 1 — номер последнего сообщения, которое «Склад» принял от приложения «Офис». В приложении «Склад», в плане обмена для узла «Офис», изменится значение поля:

    • Номер отправленного: 01

  3. «Офис» принимает сообщение от приложения «Склад» с номером 1. Из заголовка сообщения будет считан номер последнего полученного складом сообщения: ReceivedNo: 1, после чего в приложении «Офис» в плане обмена для узла «Склад» изменится значение полей:

    • Номер принятого: 01

    • Затем сообщение от приложения «Офис» будет отправлено на «Склад». В этот момент в заголовок сообщения, помимо прочих, будут записаны следующие значения:

    • MessageNo: 2 — номер сообщения, которое «Офис» отправляет на «Склад»;

    • ReceivedNo: 1 — номер последнего сообщения, которое «Офис» принял от приложения «Склад».

    • В приложении «Офис», в плане обмена для узла «Склад», изменится значение поля:

      • Номер отправленного: 12

  4. «Склад» принимает сообщение от приложения «Офис» с номером 2. Из заголовка сообщения будет считан номер последнего полученного офисом сообщения: ReceivedNo: 1, после чего в приложении «Склад» в плане обмена для узла «Офис» изменится значение полей:

    • Номер принятого: 01

    • Затем сообщение со склада будет отправлено в офис. В этот момент в заголовок сообщения, помимо прочих, будут записаны следующие значения:

      • MessageNo: 2 — номер сообщения, которое «Склад» отправляет в «Офис»;

      • ReceivedNo: 2 — номер последнего сообщения, которое «Склад» принял от приложения «Офис».

        В приложении «Склад», в плане обмена для узла «Офис», изменится значение поля:

    • Номер отправленного: 12

См. также