Практика доступа в базу 1С через протокол oData. Изменение данных

















Продолжаем знакомство с протоколом oData и в данной статье мы рассмотрим такие вопросы, как минимально необходимый багаж теоретических знаний, необходимый для работы, способы изменения доступных данных, а также с какими ограничениями можем при этом столкнуться. Осторожно, будет много скриншотов!

Эта работа является естественным продолжением моей предыдущей статьи "Практика доступа в базу 1С через протокол oData. Чтение данных" и все операции будут выполняться в той же демо-базе "Управление торговлей (базовая), редакция 10.3", к которой я предоставил доступ по OData в предыдущей статье.

 

Что нам нужно знать про HTTP?

OData — это протокол работы с данными поверх классического протокола HTTP. Это означает, что у каждого элемента данных есть свой URL, а чтобы сообщить серверу, что именно вам необходимо с этим элементом сделать (просто получить или изменить), используются HTTP-методы. Для многих эти сущности возможно будут новинкой. Ведь знание о HTTP-методах совершенно не нужно пользователям при их обычном интернет-серфинге (где тотально применяется GET). И даже веб-разработчики зачастую в курсе только про пару GET и POST, которые считают методами для отправки на сервер данных из форм.

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

  • GET — самый популярный из методов, который предназначен для запроса данных на чтение по указанному адресу;
  • POST — метод для создания нового элемента данных, в качестве адреса обычно указывают только класс объектов;
  • PUT — метод для замены свойств элемента данных на сервере по указанному полному адресу теми свойствами, которые передаются вместе с этим запросом. Обычно в популярных реализациях этого метода передача неполного состава свойств приводит к ошибке; так же часто адресация несуществующего элемента данных приводит к его автоматическому созданию (как это было реализовано в платформе 1С посмотрим ниже);
  • PATCH — метод для обновления только переданных свойств элементов данных;
  • DELETE — метод предназначенный для удаления элементов данных.

 

Клиент для протокола OData

Для "общения" с базой 1С по протоколу OData нам понадобится некоторый инструмент. И поскольку нас интересует уже не банальный GET, а полный спектр HTTP-методов, то обычные браузеры и подавляющее большинство популярных программ с поддержкой OData нам не подойдут. Потребуется что-то более функциональное.

Есть несколько распространенных вариантов. Опытные веб-разработчики, хорошо знакомые с сетевыми технологиями, на этих словах уже запускают свой любимый Fiddler, в котором на закладке Composer можно эмулировать любой из HTTP-методов, а потом, переключившись на закладку Inspectors, посмотреть полученный от сервера ответ. А поклонники UNIX-way, даже работая на Windows, конечно же имеют в наличии старый добрый автомат Калашникова консольный cUrl, в котором с помощью ключа -X можно указать требуемый HTTP-метод.

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

 Соединение = Новый HTTPСоединение(Сервер, Порт, Логин, Пароль,,,?(СоединениеЗащищено, Новый ЗащищенноеСоединениеOpenSSL(), Неопределено));
ЗапросСервера = Новый HTTPЗапрос(ПутьНаСервере);
ЗапросСервера.УстановитьТелоИзСтроки(ТелоЗапроса);
ОтветСервера = Соединение.ВызватьHTTPМетод(Метод, ЗапросСервера);
ТелоОтвета = ОтветСервера.ПолучитьТелоКакСтроку();
ЗаголовкиОтвета = "Status Code: " + ОтветСервера.КодСостояния + Символы.ПС;
Для каждого ЗначениеЗаголовка Из ОтветСервера.Заголовки Цикл
ЗаголовкиОтвета = ЗаголовкиОтвета + Символы.ПС +
ЗначениеЗаголовка.Ключ + " : " + ЗначениеЗаголовка.Значение;
КонецЦикла; 

Если захотите ознакомится с моей обработкой во вложении, то там будет дополнительно разбор переданного URL с определением протокола (HTTP или HTTPS), вычисление порта и отбрасыванием из адреса прочую вспомогательную информацию. Выглядит примерно так:

Обработка по работе с HTTP-методами

Ломать — не строить

Для начала возьмем самую простую операцию — удаление, на примере контрагента "АОЗТ Лабан" из демо базы УТ10.3. Собственно повторяем вызов строчки из выше опубликованного скриншота, но вместо метода GET воспользуемся методом DELETE. Теперь вместо ответа 200 (все хорошо), сервер нам отвечает 204 (нет содержимого) — это нормальное поведение именно для удаления.

удаление ресурсаДавайте перейдем в саму базу 1С и по журналу регистрации проверим, что же произошло:

журнал с удалениями

Как мы видим, наш контрагент был успешно удален вместе со всеми своими подчиненными связанными данными. Тот факт, что для всех  этих справочников в роли моего пользователя было запрещено интерактивное удаление, не имеет значения. Удаление по протоколу OData приравнивается к удалению из программного кода. Но, как видим, есть и различие — при программном удалении контрагента его подчиненные элементы остались бы в базе. Это важно и потому запоминаем: если у хоть одной роли пользователя есть право "Удаление", то у вас есть риск на безвозвратную потерю множества данных без контроля на наличие ссылок:

побитые данные

Кстати, повторная попытка удалить элемент с помощью метода DELETE аналогично запросу с помощью GET приведет к ошибке 404 (не найдено):

запрос удаленного

 

Создаем новое (или старое)

Как жаль, что контрагента "АОЗТ Лабан" постигла такая печальная участь… А можем ли мы его спасти без восстановления базы из бэкапа или без выполнения кода непосредственно в УТ?

Начну с цитаты из документации:

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

Больше ничего у нас с вами нет. Ни перечня обязательных полей. Ни перечня исключаемых полей. Ни упоминания о возможности создания объекта с нужным нам значением GUID. Поэтому начинаем свободные эксперименты!

Еще с самого первого запроса GET у меня осталось описание контрагента, со свойством Ref_Key, в котором находился его GUID (даже если бы его у меня не было, то я мог получить его из документа, который все еще ссылается на удаленного контрагента). Сначала попробуем отдать полностью это описание на URL с указанием элемента. Ожидаемо получаем ошибку 404 как и в случае методов GET и DELETE (см. выше). Теперь обращаемся к "набору сущностей", как того требует документация:
http://localhost/DemoTrdBase/odata/standard.odata/Catalog_Контрагенты?$format=json

И на этот раз у нас все получилось:

запрос на созданиесоздание в журнале

Более того, все получилось именно так как и было задумано — новый элемент был создан именно с тем GUID (а следовательно с той же ссылкой) как и ранее удаленный! Это хорошо видно на документе закупки ТК000000030 от 13.03.2007, где контрагент появился, но его договора и типа цен по прежнему нет (их можно аналогично восстановить, воспользовавшись в качестве образца для структуры подчиненные данные похожего контрагента, лишь в качестве GUID подставив правильные строки):

исправленный документ

Это все превосходно, но а если у объекта множество свойств и они нам сейчас не интересны (пусть будут значения по умолчанию). Можем ли мы уменьшить размер передаваемого пакета и следовательно увеличить скорость гипотетического создания множества объектов в цикле? Для ответа на этот вопрос пойдем по пути экстремальной минимизации — попробуем создать элемент не указав ему вообще ни единого свойства!

создание пустогопустой контрагентОтлично, выходит, что нам нет нужды перечислять все значения по-умолчанию и платформа за нас все сделает сама. Но справочник — это слишком просто. Интереснее попробовать с документом, при записи которого, как мы знаем, обычно возникает ошибка платформы, если не указать дату. Попробуем на примере упомянутой выше приходной накладной:

Не то чего я ожидал, но тем не менее отличный результат! Следовательно все программно-обрабатываемые события объектов не игнорируются! Это вам не тупой прямой insert в СУБД, а процедура записи полностью идентичная программной записи из какой-нибудь обработки. Но все же, что же будет с датой? Для этого нам нужен более простой документ, который крепко не привязан к рабочим процессам в УТ, к примеру Событие:

создание события без даты

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

 

Теперь будем изменять (в хорошем смысле)

Как я уже упомянул выше, для изменения данных в базе 1С посредством OData можно использовать методы PUT и PATCH.

Давайте сразу же попробуем применить PUT в созидательной роли POST. К сожалению, тут ничего интересного мы не узнаем. В контексте коллекции мы получаем ошибку, что данный метод недопустим, а при указании произвольного GUID мы получим ошибку, что изменяемый экземпляр не найден:

обновление несуществующегосоздание обновлением

А что если не указывать все реквизиты? Действительно, практика показала, что можно не указывать все реквизиты объекта и эти свойства станут заполняться значениями по умолчанию, что иногда может быть удобным. Ниже пример, где у справочника были затерты введенные вручную полное наименование и параметры прописи для валюты:

затирание свойств при обновленииВот и все интересное, что мы могли узнать про PUT, и потому переходим к более гибкому методу PATCH. При работе с этим методом, в отличии от его предшественника, нам для установки значения единичного реквизита больше не нужно делать предварительный GET для запроса значений всех свойств, что бы потом эти же свойства не затереть значениями по-умолчанию. Нам достаточно лишь идентификатора объекта и нового значения указанного свойства:

изменение свойстваТеоретически, данный метод мог бы быть очень удобным для быстрого массового изменения элементов с помощью единого вызова. На пример, чтобы сменить основного менеджера для всех поставщиков, пометить на удаление документы без суммы и так далее. К сожалению, компания 1С не дала нам такую интересную возможность; для массового изменения нам доступна лишь только серия вызовов в цикле:

попытка массового изменения

 

Итог

Не смотря на отсутствие некоторых удобств, протокол OData на платформе "1С:Предприятие 8" позволил нам совершать все базовые операции над данными. Таким образом, имея доступ в базу только по этому протоколу, можно реализовать полноценную интеграцию с некоторой внешней системой.

Статья вышла длинной не смотря на то, что были рассмотрены самые простые операции. Часть возможных интересных экспериментов была оставлена за кадром, но вы можете самостоятельно попрактиковаться. К примеру, как на счет записать набор записей по какому-нибудь из регистров? 😉

26 Comments

  1. Adam12345678

    Интересная статья, спасибо.

    Reply
  2. DenisCh

    Соглашусь. Интересно.

    Reply
  3. McSim_

    «На самом интересном месте!..» 🙂

    Как раз запросы к регистрам — самое интересное. Например, как получить сальдо на выбранном счёте на выбранную дату? Об этом информации в сети минимум.

    Reply
  4. baracuda

    Лайк тигру)

    Reply
  5. Dementor

    (3) в третьей части как раз хотел поиграться с виртуальными таблицами, блокировками, режимом загрузки и прочими «функциями».

    Reply
  6. Vladimir Litvinenko

    В записи данных в 1С через OData, есть большая опасность, которая может дать сильного пинка архитектору системы при активном использовании. В GRASP есть фундаментальный шаблон Information Expert, более известный под общим названием «инкапсуляция». Его нарушение ведет к детским болезням программирования, последствия же для системы в целом могу оказаться совсем не детскими.

    Если обращение на запись через OData выполняет более чем одна внешняя система, то даже изменение типа реквизита может превратиться в настоящую эпопею с подключением всех разработчиков всех этих внешних систем. Не говоря уже о скованности по рукам и ногам при изменении алгоритмов записи/проведения внутри системы принимающей данные. Заканчивается это либо тем, что на развитие системы построенной на OData «забивают», ввиду сложности изменений и необходимости постоянно координировать взаимодействие множества разработчиков, либо развитие продолжается, но титаническими неоправданными усилиями. Ну или еще один путь — переписать все с применением более подходящих технологий ))

    Конечно это не в целом к технологии OData и REST относится. Просто в 1С подход так реализован, что сложно для OData красивый интерфейс сделать, с возможностями хоть как-то напоминающими web-сервисы или хотя бы http-сервисы. Единственный интерфейс — этот тот что предлагает платформа без возможности его изменения, при этом он больше напоминает прямую запись в SQL …. в каждую таблицу отдельно…. без транзакций )) Ибо оптимистические блокировки не сильно помогают в борьбе за целостность данных.

    Для 1С сейчас OData хорош только в универсальных алгоритмах, где изменение типа реквизита, появление обязательного к заполнению реквизита или изменение алгоритма обработки входящих данных не ведет к катастрофам. Для этого в алгоритмах отправки данных надо анализировать данные /odata/standard.odata/$metadata. Но многие ли так делают? Из известных публикаций только Metadata.js вспоминается.

    Пока что имхо OData в 1С лучше применять на чтение. И в тех случаях, когда временный сбой в чтении данных не скажется сильно на работе всей системы.

    Reply
  7. Dementor

    (6) Спасибо за комментарий. Если его перевести на обычный язык, то вы хотели написать, что 1) при одновременной работе с интерфейсом нескольких клиентов возможны проблемы логической целостности; 2) при изменении метаданных базы 1С возникают проблемы в скриптах доступа. Ничего не пропустил?

    Reply
  8. Dos_1985

    Спасибо за статью

    Reply
  9. Vladimir Litvinenko

    (7) Примерно так. По первому пункту проблема скорее даже не с количеством клиентов, а с тем, разные группы разработчиков отвечают за эти системы или это одна и та же команда. Скоординировать изменения кода в разнородных системах только потому, что произошли простейшие изменения в структуре объекта метаданных — сложная задача. При наличии же нормального интерфейса вроде web-сервиса или хотя бы http-сервиса рефакторинг или изменение логики происходит значительно проще.

    По этим признакам реализация OData от 1С больше похожа на COM-подключение. Из плюсов — протокол http и кросплатформенность. Но ограничений еще больше: экспортные методы, целостность и согласованность данных, проверки при записи и т.д. Также нет объектной обертки к OData. Для взаимодействия между системами на 1С приходится писать обертки самостоятельно, чтобы в коде не было «простыни». Это облегчает ряд задач, но поскольку обертку можно применять только для алгоритмов отправки (на стороне клиента), то от главных проблем это увы не спасает.

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

    Reply
  10. Alien_job

    Спасибо за статью. Про ошибку при записи документа прокомментируете? У вас не написано что получилось изменить существующий в базе документ

    Reply
  11. Dementor

    (10)

    У вас не написано что получилось изменить существующий в базе документ

    С помощью POST это действительно невозможно. И это хорошо — должен же быть хоть какой-то порядок 🙂 С методами PUT и PATCH нет никаких проблем по изменению существующих документов, если известен их идентификатор — в моих примерах документы были успешно модифицированы.

    Reply
  12. Alien_job

    (11) Ок, перепробую. Подскажете платформу на которой вы работаете?

    Reply
  13. Dementor

    (12) сейчас установлена 8.3.11.2867. На ней же сделаны примеры из статьи.

    Reply
  14. kauksi

    Все эти действия через oData напоминают известный анекдот… «про любителей секса с 1с в противогазе, стоя и в гамаке»

    Reply
  15. Dementor

    (14) Да не вопрос! Предложите более простой способ прочитать и изменить произвольные данные в базе 1С для стороннего программного комплекса без внесения изменений в саму базу 1С. И что бы на линуксах и маках работал.

    Reply
  16. kauksi

    (15) Всегда есть выбор: «толкать» данные или «тянуть». Пока что «тянуть извне» разнообразными средствами 1с гораздо проще чем «толкать в 1с» из линукса по oData.

    Reply
  17. kauksi

    ну либо использовать какую-нибудь промежуточную шину ESB, чтобы получать данные из сторонней системы и потом толкать их в 1с каким то общеизвестным методом. А то что вы описываете выше это интересно, но все же как ассемблер для 1с ввиду узкой спецификации

    Reply
  18. Dementor

    (16) Для программиста легче. А для какого-нибудь веб-мастера все с точностью наоборот.

    Reply
  19. mikeA

    (15) По-моему ключевое слово здесь «без внесения изменений в конфигурацию». Однако когда дело доходит до доступа в базу по http внесение изменений в конфигурацию уже не представляет из себя проблему. И в этом случае гораздо удобнее http сервисы. Да, это не универсально, но плюсы таки да перевешивают.

    Reply
  20. Dementor

    (19) Согласен, что при наличии выбора SOAP или HTTP-сервис, последние имеют ряд преимуществ (как сравнивать ручной ввод новой НСИ и загрузку из Excel).

    Но если речь идет про базы на поддержке и автообновлении, то все не так однозначно. Так же есть случая, когда компания купила коробку и более тратится на программиста не хочет, но обладает софтом, который умеет работать с SOAP. Можно сказать, что это «нишевая потребность», которая актуальна не для всех (так же как работа с двоичными данными или выражениями XPath).

    Reply
  21. maxx

    Я как-то уже писал на форуме 1с, что при создании новых объектов через Odata не хватает метода Заполнить (вызов события ОбработкаЗаполнения)

    Reply
  22. la@pivoluchshe.ru

    Скачал Вашу обработку, запускаю на 1С Розница, редакция 2.2 (2.2.7.39) (1С:Предприятие 8.3 (8.3.11.2899)). Обработка запускается, но список объектов пустой. Подскажите, что сделать, чтобы обработка сработала?

    Мне нужно именно для Розницы, для УТ воспользовался стандартной обработкой.

    Спасибо

    Reply
  23. burnand2

    Добрый день.

    Пытаюсь создать документ методом POST выдает ошибка 500: Не удалось записать документ.

    Подскажите в чем может быть ошибка?

    Reply
  24. Dementor

    (23) я не помню какая ошибка при отказе в доступе по правам — возможно именно тут проблема. Или в алгоритмах ПередЗаписью, ПриЗаписи, ПриОтменеПроведения или ПриПроведении выставляется Отказ = Истина. Или банально ошибка в коде.

    Ваши действия: 1) проверить журнал регистрации на предмет ошибок и сообщений про недостаток прав, 2) проверить права роли подключения и 3) если не получилось разобраться, подключится в отладке.

    Reply
  25. user1203390

    (24) А как решить проблему с 500 ошибкой при создании документа? У меня последний релиз Управление автотранспортом. По протоколу oData есть возможность выбрать все документы (Путевой лист) или конткретный по условию. Но get через http://host/Base/odata/standard.odata/Document_уатПутевойЛист(guid‘key’)/ возвращает ошибку 500, также как и POST PATCH запросы. Другие документы создаются и меняются(проверял только те, которые использую). Через http сервис отладкой выбрасывает сразу, нет возможности посмотреть откуда идёт ошибка. В какую сторону нужно смотреть?

    Reply
  26. e-9

    (25) в (24) в принципе уже отвечено

    посмотрите в тело http-ответа — там могут быть подробности. Вот мне, например, в теле ответа пришло сообщение, что поле Date не заполнено. Заполнил — ушла ошибка 500.

    Правда, вы непонятно пишете — то ли при создании/изменении, то ли при Get, ошибка 500 у вас?

    Reply

Leave a Comment

Ваш адрес email не будет опубликован. Обязательные поля помечены *