DB-Aware контролы в Delphi значительно упрощают жизнь разработчикам GUI-программ работающих с базами данных. Они многое делают сами без написания кода – отображают данные, позволяют пользователям их модифицировать и сохраняют изменения в базу данных. Но, что делать, если данные хранятся не в базе данных, а в массиве, списке, объекте или какой-нибудь другой структуре? Можно воспользоваться "memory table" – потомком TDataSet, который хранит данные в памяти. Скопировать в него данные, отобразить, обработать и скопировать обратно. Вариантов таких "memory table" много: TClientDataSet, TFDMemTable из FireDAC, TkbmMemTable, TVirtualTable из UniDAC, TMemTableEh из EhLib... Но есть способ решить этот вопрос проще, без копирования данных туда-сюда.
Язык программирования самого высокого уровня содержит всего несколько команд для управления программистами
Показаны сообщения с ярлыком DataSet. Показать все сообщения
Показаны сообщения с ярлыком DataSet. Показать все сообщения
24 августа 2021
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:
Еще, как зануда, отмечу, что вещи в стиле
Так, что господа, те кто считает себя программистом, дружите с Try...Finally...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.... 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;
Еще, как зануда, отмечу, что вещи в стиле
необходимо использовать совместно с конструкцией Try...Finally...End, т.к. если между этими строчками во время выполнения программы произойдет ошибка, то курсор не будет восстановлен. Т.е. нужно было написать так:Screen.Cursor := crHourGlass; ... Screen.Cursor := crDefault;
А еще к восстановлению курсора в блок Finally...End было бы неплохо, для высвобождения памяти распределенной при вызове GetBookmark, добавить DataSet.FreeBookmark(b). Это же элементарно – для всех изменяемых или создаваемых ресурсов, на случай ошибки, нужно гарантировать возвращение их к исходному состоянию или высвобождению занимаемой ими памяти.Screen.Cursor := crHourGlass; Try ... Finally Screen.Cursor := crDefault; End
Так, что господа, те кто считает себя программистом, дружите с 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;
Что бы загрузить массив в параметр 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), для работы с которыми используются процедуры:
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 :)
- 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 :)
Подписаться на:
Сообщения (Atom)