zoukankan      html  css  js  c++  java
  • 记录一偏,因为我不会翻译,

    Delphi XE5 и MongoDB (продолжение)

    Продолжаем конспект из предыдущего поста http://blogs.embarcadero.com/asovtsov/index.php/archives/615, посвященного разбирательству, можно ли разрабатывать приложения на Delphi XE5, получающие и сохраняющие данные в БД MongoDB.

    Установка драйвера, сборка тестовых примеров и поверка их прошли без особых проблем.

    Как выглядит технология обращения к MongoDB из примера программы на Delphi? Заглянем внутрь примера AddressBook.

    const
      db = 'test';
      ns = db + '.addresses';
    
    ...
    
    initialization
      mongo := TMongo.Create();
      if not mongo.isConnected() then begin
        ShowMessage(NoConnectMsg);
        Halt(1);
      end;
      mongo.indexCreate(ns, 'phone');

    Соединение с сервером открывается сразу же при инициализации приложения.  Здесь используются значения по-умолчанию: localhost:27001. Поэтому нет установок свойств объекта коннекции.

    Дальше видны особенности архитектуры СУБД и драйвера.

    MongoDB это документ-ориентированная БД. Хранит "документы" - иерархические объекты, максимально близкие по структуре с JSON-объектами. Имеется мощный язык запросов, основные компоненты которого являются такими же объектами. Поэтому, так легко работать с запросами и их результирующими наборами данных из языков JavaScript, Python и т.п. Для обеспечения максимального быстродействия внутри эти документы хранятся в формате BSON - "binary JSON". Библиотека доступа содержит классы для работы с BSON. Для сериализации параметров запросов и полей для записи служат методы класса TBsonBuffer, учитывающие особенности представления типов элементов данных. Тем не менее, отсутствует метод (или класс), чтобы напрямую сериализовывать JSON-объект в запрос или документ. Результат запроса представляется объектом класса TBson, предоставляющего способы работы с каждым типом элементов данных и для итерации по BSON-документу, но не дающего метода десериализации BSON в строку или JSON-объект.

    В рассматриваемом примере это и не требуется, там с успехом применяются существующие методы формирования BSON-запросов и чтения BSON-результатов.

    procedure TForm1.btnSaveClick(Sender: TObject);
      var
        bb : TBsonBuffer;
        b : TBson;
        query : TBson;
    begin
      query := BSON(['phone', txtPhone.Text]);
      if (mongo.findOne(ns, query) = nil) Or
        (MessageDlg('A record already exists with that phone number.  Replace?', mtWarning, [mbYes, MbNo], 0) = mrYes) then begin
          bb := TbsonBuffer.Create();
          bb.append('name', txtName.Text);
          bb.append('address', txtAddress.Text);
          bb.append('city', txtCity.Text);
          bb.append('state', txtState.Text);
          bb.append('zip', txtZip.Text);
          bb.append('phone', txtPhone.Text);
          b := bb.finish();
          mongo.update(ns, query, b, updateUpsert);
          ShowMessage('Record saved.');
        end;
    end;
    Далее...

    Программисты на Delphi привыкли к тому, как легко создаются приложения, работающие с базами данных, при помощи компонентной парадигмы Datasets. Идея состоит в том, что если удастся "поместить" результат запроса в объект типа TDataset, в дальнейшем можно работать с таким набором документов стандартными методами, в том числе, из таких привычных элементов UI, как гриды.

    До выхода XE5 единственным вариантом работы с MongoDB в рамках этой парадигмы оставался вариант с применением DataSnap и RESTful вызовов. Чтобы избежать этого, надо написать специализированный dataset - адаптер, что, хотя и реализуемо на практике, влечет за собой большой объем изучения и практического освоения "внутренней кухни" технологий   компонент Delphi для обращения к БД. В версии XE5 содержится более "продвинутая" технология DataSnap, в составе которой уже есть компонент TRESTresponseDatasetAdapter, предназначенный для обработки ответов на REST-вызовы в формате JSON-документов и помещения их в указанный TDataset. Поскольку результаты запросов Mongo максимально близки по формату к JSON, есть надежда быстро решить поставленную задачу "малой кровью".

    Первое: нужно сериализовать результат запроса из BSON в JSON. Задача  быстро и сравнительно просто была решена мною созданием TBSONStreamer -наследника от Tbson, который "умеет" сериализовать BSON в передаваемый ему TStream в виде текста в структуре JSON.

    Для демонстрации и проверки принятых решений было построено приложение, состоящее из единственной формы, на которой были размещены контролы для ввода запроса и отображения результатов, в том числе стандартный TDBGrid, соединенный с Tdatasource, связанный с TClientDataset.

    В качестве источника была выбрана база данных документов о проведенных мною вебинаров по продуктам Embarcadero. Запрос формируется пользователем в ListBox ‘Запрос’, какие поля включать в результирующие документы - в Listbox ‘Показ полей’. Выполнение запроса происходит по кнопке Run Query.

    Для работы TRESTResponseDataSetAdapter необходимо присутствие TRESTResponse, хотя при обработке запроса он не используется.

    procedure TForm2.ShowBResults(bsonobj: TBSON);
    var
       stm: TStringStream;
       btm: TBSONStreamer;
       i: integer;
    begin
      stm := TStringStream.Create();
      btm := TBSONStreamer.Create;
      try
        if bsonobj = nil then
          stm.WriteString('nil BSON'+#13#10)
        else begin
          stm.WriteString('{'+#13#10);
          btm._displayS(stm, bsonobj.iterator, 1);
          stm.WriteString(#13#10+'}');
          stm.Position:=0;
          memo1.Lines.LoadFromStream(stm);
          stm.Position:=0;
          TCustomRESTResponse(RESTResponse).SetContent(stm);
          with ClientDataSet do begin
            for i := 0 to Fields.Count-1 do
              Fields.Fields[i].displaywidth := 10;
          end;
        end;
      finally
        stm.Free;
        btm.Free;
      end;
    end;

    После получения результата запроса (один документ для пробы) он отображается в нижней части формы в виде JSON. Затем этот  же документ через TRESTResponseDatasetAdapter передается в ClientDataset и отображается в гриде.  Хотя TRESTResponseDatasetAdapter не имеет средств использования JSON-данных минуя объект RESTResponse, удалось считать данные, воспользовавшись унаследованным защищенным методом класса-предка адаптера.  После загрузки данных в dataset были установлены читабельные размеры колонок. Результаты представлены на картинке ниже.

    Итоги:

    1. Удалось применить стандартные библиотеки и драйвера для "прямого" доступа к MongoDB из программы на Delphi XE5 без применения DataSnap и Http-вызовов
    2. Проблема сериализации BSON была решена написанием простого "потомка" TBSON
    3. Удалось воспользоваться компонентом TRESTResponseDatasetAdapter для передачи данных результирующего набора запроса к MongoDB в стандартный Dataset и работать с ним в дальнейшем при помощи общеупотребимых компонент.
    4. Предлагаемый создателями драйвера механизм создания запросов и документов для записи в БД очень неудобен и требует замены на более user-friendly для формулирования подобных документов прямо на JSON. Преобразование JSON-BSON должно быть скрыто от программиста, так как это сделано в Node.js и Python, например.
    5. Хотя поставленная цель была достигнута, сама поддержка JSON классом TRESTResponseDatasetAdapter имеет ряд недостатков: например, он позволяет работать с документами только в режиме чтения, без модификации. Можно было бы и создавать поля TField типа ftDataset для вложенных поддокументов и массивов, допустимых в стандарте JSON. Есть недостатки в поддержки кодировок текста.

    Словом, для создания хорошего, а не удовлетворительного механизма работы с MongoDB, нужно создать более совершенные адаптеры для работы с JSON/BSON объектами и передачи их в TDataset.

    Вот одна из идей вариантов задания для участия в будущих конкурсах нашей компании. Дерзайте, дельфисты! Никто не может игнорировать практически самую стремительно развивающуюся технологию обработки данных!

    发源地   http://blogs.embarcadero.com/asovtsov/index.php/archives/632/

  • 相关阅读:
    C++课程学习笔记第六周:多态
    C++课程学习笔记第五周:继承
    C++课程学习笔记第四周:运算符的重载
    C++课程学习笔记第三周:类和对象提高
    C++课程学习笔记第一周:从C到C++
    C++课程学习笔记第二周:类和对象基础
    PyTorch的安装及学习资料
    PyTorch练手项目一:训练一个简单的线性回归
    PyTorch练手项目二:MNIST手写数字识别
    PyTorch练手项目四:孪生网络(Siamese Network)
  • 原文地址:https://www.cnblogs.com/key-ok/p/3530196.html
Copyright © 2011-2022 走看看