Показаны сообщения с ярлыком DataSet. Показать все сообщения
Показаны сообщения с ярлыком DataSet. Показать все сообщения

24 августа 2021

Работа с любыми структурами данных через DB-Aware контролы

    DB-Aware контролы в Delphi значительно упрощают жизнь разработчикам GUI-программ работающих с базами данных. Они многое делают сами без написания кода – отображают данные, позволяют пользователям их модифицировать и сохраняют изменения в базу данных. Но, что делать, если данные хранятся не в базе данных, а в массиве, списке, объекте или какой-нибудь другой структуре? Можно воспользоваться "memory table" – потомком TDataSet, который хранит данные в памяти. Скопировать в него данные, отобразить, обработать и скопировать обратно. Вариантов таких "memory table" много: TClientDataSet, TFDMemTable из FireDAC, TkbmMemTable, TVirtualTable из UniDAC, TMemTableEh из EhLib... Но есть способ решить этот вопрос проще, без копирования данных туда-сюда.

04 декабря 2019

Ходячие мертвецы. BDE в Delphi 10.3 Rio

    В лихие 90-е... т.е. в далекие 90-е компания Borland для своих средств разработки придумала единый программный интерфейс для доступа к базам данных - "Open Database Application Programming Interface" (ODAPI). Он успешно прошел апробацию в ее первых версиях средств разработки для настольных баз данных под Windows: Quattro Pro, Paradox и dBase. Вскоре функционал ODAPI был расширен поддержкой SQL-серверов и возможностью выполнять SQL-запросы, как к серверным БД, так и к настольным. Его даже поддержали такие "уважаемые" компании как IBM и Novell, а компания Microsoft подхватила идею и выпустила свой подобное API - ODBC. Позже в названии слово "open" было заменено на "integrated" и под названием "Integrated Database Application Program Interface" (IDAPI) данная технология вошла в "Borland Database Engine" (BDE). Но BDE постигла судьба многих других продуктов, конкурировавших с Microsoft - лучший по функциональным возможностям программный продукт проиграл маркетинговую войну.

12 ноября 2019

SQL доступ к Elasticsearch


    Что делать, если вы хотите использовать SQL-запросы к Elasticsearch, но не купили X-Pack и у вас нет доступа к Elasticsearch SQL?

Вариант первый: смириться и продолжить писать REST-запросы

Вариант второй: использовать специальную библиотеку для SQL-доступа к Elasticsearch. Например, CData Elasticsearch Driver. Она существует в множестве вариантов и позволяет получить доступ к данным в Elasticsearch из любых средств разработки и программ (FireDAC Components, ADO.NET Provider, ODBC Driver, JDBC Driver, Power BI Connectors, BizTalk Adapter, PowerShell Cmdlets, Excel Add-In, Anypoint Connectors, SSIS Component).

Рассмотрим использование CData FireDAC Components for Elasticsearch в Delphi.

24 октября 2015

Изучайте используемый инструментарий!

   Вчера начал разбираться с чужим проектом на Delphi 7. Система весьма сложная – несколько взаимосвязанных АРМов по 20-50 форм (а может и больше, точно не считал). Усложняет все то, что она разрабатывается уже давно и пережила смену нескольких команд разработчиков. Каждая команда приносила в проект свои инновации. Например, одна из них перевела доступ к БД Oracle с BDE на ADO. При этом все старые объекты для работы с базами через BDE (TDatabase, TTable, TQuery и TStoredProc) продолжают лежать на формах рядом с их копиями для работы через ADO (TADOConnection, TADOTable, TADOQuery и TADOStoredProc). Они даже клонировали объекты TDataSource для ADODataSet'ов. Все замеченные беглым взглядом "интересные" моменты перечислять не буду, а вернусь к заголовку этой заметки. Одна из команд добавила в проект DBGridEh из EhLib 6.0 в компанию к стандартному DBGrid'у. Хороший выбор grid'а, одобряю ;-) Хочу поделится с вами их реализацией сортировки по клику на заготовке колонки. К каждому DBGridEh'у, подчеркиваю - к каждому DBGridEh'у, был написан обработчик OnSortMarkingChanged:
...
dsXYZ: TDataSource;
gridXYZ: TDBGridEh;
...
procedure TfmMain.gridXYZSortMarkingChanged(Sender: TObject);
var
  i: Integer;
  s: String;
  b: TBookmark;
begin
  Screen.Cursor := crHourGlass;
  b := dsXYZ.DataSet.GetBookmark;
  s := '';
  for i := 0 to gridXYZ.SortMarkedColumns.Count - 1 do
    begin
     s := s + gridXYZ.SortMarkedColumns[i].FieldName;
     if (gridXYZ.SortMarkedColumns[i].Title.SortMarker = smDownEh) then
        s := s + ' DESC';
     s := s + ';';
    end;
  TADODataSet(dsXYZ.DataSet).IndexFieldNames := s;
  dsXYZ.DataSet.GotoBookmark( b );
  Screen.Cursor := crDefault;
end;
   В одном из АРМ'ов только на главной форме больше 20 DBGridEh'ов лежащих на страницах TNotebook. И на каждый был написан свой обработчик! Если говорить о Delphi, или о объектно-ориентированном программировании в целом, то почему бы все эти десятки одинаковых обработчиков не заменить на один, где вместо gridXYZ использовать TDBGridEh(Sender) (или (Sender as TDBGridEh)), а вместо dsXYZ.DataSet использовать TDBGridEh(Sender).DataSet? Но самое интересное, что для сортировки в DBGridEh и такого обработчика писать не надо. EhLib для автоматической сортировки данных в DataSet'е имеет набор специальных объектов и от программиста требуется только добавить в раздел "uses" любого модуля в проекте один из модулей EhLibXXX (EhLibBDE, EhLibADO, EhLibCDS... в зависимости от подключенного к grid'у DataSet'а). Таким образом, вместо написания и копипаста десятков обработчиков OnSortMarkingChanged нужно было всего лишь подключить к проекту небольшую юниту EhLibADO.

   Еще, как зануда, отмечу, что вещи в стиле
Screen.Cursor := crHourGlass;
... 
Screen.Cursor := crDefault;
необходимо использовать совместно с конструкцией Try...Finally...End, т.к. если между этими строчками во время выполнения программы произойдет ошибка, то курсор не будет восстановлен. Т.е. нужно было написать так:
Screen.Cursor := crHourGlass;
Try
 ...
Finally
 Screen.Cursor := crDefault;
End
   А еще к восстановлению курсора в блок Finally...End было бы неплохо, для высвобождения памяти распределенной при вызове GetBookmark, добавить DataSet.FreeBookmark(b). Это же элементарно – для всех изменяемых или создаваемых ресурсов, на случай ошибки, нужно гарантировать возвращение их к исходному состоянию или высвобождению занимаемой ими памяти.

   Так, что господа, те кто считает себя программистом, дружите с Try...Finally...End и главное - ИЗУЧАЙТЕ ИСПОЛЬЗУЕМЫЙ ИНСТРУМЕНТАРИЙ!!!

18 июня 2012

Хранение массива в BLOB-поле - версия 2

    Комментарий Алексея Тимохина к моей заметке "Хранение массива в BLOB-поле" навел меня на мысль, что приведенный мной код можно значительно упростить, если выбросить из него использование TMemoryStream для временного хранения информации.
    Что бы загрузить массив в параметр query типа ftBlob можно использовать метод SetBlobData:

qInsertResearchData.Params[5].SetBlobData(aData, Length(aData) * SizeOf(aData[0]))

Чтение массива из поля типа TBlobField тоже можно записать коротко:

  // Установка размера динамического массива aData
  SetLength(aData, qResearchDATA.BlobSize div SizeOf(aData[0]));
  // Запись содержимого поля qResearchDATA типа TBlobField в массив aData
  qResearch.GetBlobFieldData(qResearchDATA.FieldNo, TBlobByteData(aData))

    Т.к. размер массива я устанавливаю равным размеру содержимого BLOB-поля, то для исключения лишних проверок в GetBlobFieldData я заменил вызов этого метода на свой код и теперь запись содержимого поля qResearchDATA типа TBlobField в массив aData выглядит так:

  With qResearch.CreateBlobStream(qResearchDATA, bmRead) do
    Try
      ReadBuffer(aData[0], qResearchDATA.BlobSize);
    Finally
      Free;
    End;

24 марта 2010

Delphi 2010: TDataSet.FreeBookmark – рудимент

   Часто бывает полезно отметить текущее положение курсора в DataSet'е так, чтобы позже можно было быстро возвратиться к этому месту. Delphi обеспечивает эту функциональную возможность с помощью закладок (Bookmark), для работы с которыми используются процедуры:
  • GetBookmark – устанавливает закладку на текущую запись;
  • BookmarkValid – проверяет, существует ли запись, на которую ссылается закладка;
  • GotoBookmark – позиционирует курсор на запись, на которую ссылается закладка;
  • FreeBookmark – освобождает системные ресурсы, используемые методом GetBookmark.
Думаю это знакомая многим конструкция:

Var
  q: TSDQuery;
  bm: TBookmark;
begin
  Try
    bm := q.GetBookmark; // делаем закладку
    // обрабатываем ds
  Finally
    If bm <> nil then
      begin
        If q.BookmarkValid(bm) then
          q.GotoBookmark(bm);
        q.FreeBookmark(bm);
      end;
  End;
end;

В Delphi 7 код FreeBookmark выглядит так:

procedure TDataSet.FreeBookmark(Bookmark: TBookmark);
begin
  FreeMem(Bookmark);
end;

В Delphi 2010 он – просто заглушка:

procedure TDataSet.FreeBookmark(Bookmark: TBookmark);
begin
  // No longer need to free bookmark since it's a TBytes now.
end;

   Т.е. FreeBookmark в Delphi 2010 – это уже пережиток прошлого и вызывать его больше не нужно. Таким образом, исходный код становится проще:

Var
  ds: TSDQuery;
  bm: TBookmark;
begin
  Try
    bm := q.GetBookmark; // делаем закладку
    // обрабатываем ds
  Finally
    If (bm <> nil) and q.BookmarkValid(bm) then
      q.GotoBookmark(bm);
  End;
end;

   P.S. А вот справочную систему Delphi 2010 подправить, как всегда, забыли. В ней есть раздел "DB.TDataSet.FreeBookmark" с описанием процедуры и рекомендацией ее использования. А раздел "Marking and Returning to Records" содержит строку "FreeBookmark frees the memory allocated for a specified bookmark when you no longer need it. You should also call DB.TDataSet.FreeBookmark before reusing an existing bookmark." и пример, где используется FreeBookmark :)