返回文章列表

行動應用程式嵌入式資料函式庫實作

本文示範如何使用 Delphi 和 FireDAC 建立一個簡單的待辦事項行動應用程式,利用嵌入式 SQLite 資料函式庫儲存資料。文章涵蓋應用程式架構設計、資料函式庫選擇、FireDAC 連線設定、資料表設計以及 CRUD 操作實作等關鍵步驟,並提供程式碼範例與詳細解說,幫助開發者快速上手。

行動應用開發 資料函式庫

Delphi 行動應用程式開發中,資料儲存至關重要。本文以待辦事項應用程式為例,講解如何使用嵌入式 SQLite 資料函式庫和 FireDAC 進行資料管理。首先,我們將應用程式分為 UI、資料存取層和共用單元三個部分,降低耦合度,提高可維護性。接著,選擇 SQLite 作為嵌入式資料函式庫,並使用 FireDAC 建立資料函式庫連線。我們定義了 TToDo 記錄型別表示待辦事項,並使用 TToDos 泛型列表儲存多個待辦事項。為了抽象資料函式庫操作,我們設計了 IToDoData 介面,定義了 CRUD 操作方法。最後,我們示範瞭如何使用 FireDAC Connection Editor 建立資料函式庫表格,並在行動裝置上初始化資料函式庫連線和實作 IToDoData 介面,完成待辦事項應用程式的資料存取功能。

使用嵌入式資料函式庫建立待辦事項應用程式

在這一章中,我們將逐步建立一個簡單的行動應用程式,使用嵌入式資料函式庫來管理待辦事項列表。在開始編寫程式碼之前,讓我們先了解整體的應用程式架構。系統越複雜,正確的架構就越重要。

典型的開發方法是將大問題分解為較小、更容易解決的問題。在軟體開發中,最常見的方法是將整個系統分成明顯分離的層級。在資料驅動的應用程式中,我們至少可以識別出兩個邏輯部分:使用者介面(UI)和資料存取邏輯。清楚地分離這兩個層級可以實作外掛架構,讓 UI 能夠以標準方式連線到不同的資料存取模組,並且可以在不影響底層資料存取層的情況下替換 UI。

在 Delphi 應用程式的上下文中,我們可以將專案分成三個獨立的實體,如 圖 10.1 所示:

  • 一個或多個視覺表單,用作圖形使用者介面(GUI)
  • 一個或多個資料模組,包含非視覺元件,用於與資料函式庫互動
  • 一個或多個獨立單元,包含通用型別和實用函式,供應用程式的兩個層級使用

圖 10.1:簡單資料函式庫應用程式的整體架構

此圖示展示了資料函式庫應用程式的基本架構,包括 UI、資料存取層以及共用單元。

圖表翻譯: 圖 10.1 展示了一個典型的三層架構,包括使用者介面、資料存取邏輯以及分享的通用單元。這種設計使得各層之間的耦合度降低,便於維護和擴充套件。

現在讓我們在 Delphi 中建立這個結構:

  1. 建立一個新的多裝置空白 Delphi 專案。將主表單單元另存為 uFormToDo,並將整個應用程式另存為 ToDoList。將表單的 Name 屬性更改為 FormToDo
  2. 從 Delphi 主選單中選擇 檔案 | 新增 | 資料模組。將資料模組的 Name 屬性更改為 DMToDo,並將其另存為 uDMToDo
  3. 現在,從 Delphi 主選單中選擇 檔案 | 新增 | 單元,為專案新增一個空白單元。將其另存為 uToDoTypes

現在,您應該擁有一個具有 圖 10.2 所示結構的專案。

圖 10.2:在 Delphi 中簡單資料函式庫應用程式的專案結構

此圖示展示了專案在 Delphi 中的組織結構,包括不同的單元和模組。

圖表翻譯: 圖 10.2 詳細展示了專案在 Delphi 中的檔案結構,包括主要的表單單元、資料模組以及共用的型別單元。

我們的專案由三個不同的單元組成,分別代表資料驅動應用程式的三個主要構建塊。現在,讓我們在這三個單元之間建立依賴關係。uToDoTypes 單元不依賴於專案中的其他單元,因此無需在其 uses 子句中新增任何內容。該單元需要被 UI 和資料存取邏輯同時使用。使用 檔案 | 使用單元 命令,將 uToDoTypes 單元新增到表單和資料模組的 interface 部分的 uses 子句中。

現在,將資料模組 uDMToDo 新增到主表單單元的 implementation 部分的 uses 子句中。這應該與 圖 10.1 中所示相符。

這是我們將在本章後續章節中繼續構建的應用程式的起點。在本文中,我們開始建立整體應用程式結構,並開始研究我們需要開發的每個區域。

建模資料

uToDoTypes 單元是用於新增在 UI 和資料存取模組之間共用的資料型別的。在本例中,我們需要定義一個代表待辦事項的型別。我們需要在記錄(record)和類別(class)之間做出選擇。記錄不需要擔心記憶體管理,通常效能優於物件。然而,將我們的“資料包裝器”型別定義為物件也是一個不錯的選擇。記錄型別不能被繼承,在更複雜的場景中,使用物件所帶來的靈活性可能使其比記錄更合適。

一個待辦事項應該具有哪些屬性?為了保持簡單,讓我們新增一個 Title 和一個 Category 字串欄位。在資料函式庫中,為任何給定的專案都有一個識別符號是很方便的,通常這是一個整數值。

以下是我們如何在 uToDoTypes 單元中表示待辦事項:

type
  TToDo = record
    Id: integer;
    Title: string;
    Category: string;
  end;

  TToDos = TList<TToDo>;

內容解密:

  • TToDo 是一個記錄型別,用於表示單個待辦事項,包含 IdTitleCategory 三個欄位。
  • TToDosTToDo 的泛型列表,用於儲存多個待辦事項,方便在資料模組中傳回所有待辦事項的列表。
  • 使用記錄型別可以避免手動管理記憶體,提高效能。
  • 泛型列表提供了型別安全和便利的操作方法。

接下來的步驟是定義資料模組應該提供的標準操作。在資料函式庫領域,這通常被稱為 CRUD 操作。這個縮寫代表建立(Create)、讀取(Read)、更新(Update)和刪除(Delete)。由於我們的資料模型中只有一個實體,這些操作應該由四個不同的方法實作。我們還想新增第五個方法,即列出記錄的功能。

為了抽象這些操作,讓我們宣告一個新的介面型別,稱為 IToDoData,它將定義我們的資料模組應該提供的功能:

type
  IToDoData = interface
    function ToDoCreate(AValue: TToDo): Integer;
    function ToDoRead(Id: Integer; out AValue: TToDo): Boolean;
    function ToDoUpdate(AValue: TToDo): Boolean;
    function ToDoDelete(Id: Integer): Boolean;
    procedure ToDoList(AList: TToDos);
  end;

內容解密:

  • IToDoData 介面定義了對待辦事項進行 CRUD 操作的方法。
  • ToDoCreate 方法用於建立新的待辦事項,並傳回新專案的識別符號。
  • ToDoRead 方法根據給定的 ID 讀取待辦事項,並將其儲存在輸出的 AValue 引數中。
  • ToDoUpdate 方法用於更新現有的待辦事項。
  • ToDoDelete 方法根據給定的 ID 刪除待辦事項。
  • ToDoList 方法用於檢索所有待辦事項,並將其儲存在提供的 TToDos 列表中。

這是一種相當常見的表示 CRUD 操作的方式。透過定義這個介面,我們可以實作資料存取邏輯與 UI 的分離,使得我們的應用程式具有更好的可擴充套件性和維護性。

選擇資料函式庫的考量與實作

在開發行動應用程式時,資料儲存是一個至關重要的環節。大部分的行動應用程式都需要處理資料,若沒有適當的資料儲存方案,將會對應用程式的功能與使用者經驗造成影響。在設計應用程式時,開發者需要面對的首要架構決策之一就是選擇適當的資料儲存方式。

為何需要本地資料儲存?

雖然雲端儲存是目前的主流解決方案,但在缺乏網路連線的情況下,應用程式仍需要能夠正常運作並存取最新的資料。因此,在裝置上進行本地資料儲存是必要的。

簡易的資料儲存方案

在簡單的情況下,將資料儲存為純文字或二進位檔案是一種可行的方案。然而,對於更複雜的資料管理需求,嵌入式資料函式庫系統(embedded database system)通常是更好的選擇。

嵌入式資料函式庫的選擇

對於行動裝置上的Delphi應用程式,主要有兩種嵌入式資料函式庫可供選擇:

  1. InterBase:由Embarcadero開發的SQL關聯式資料函式倉管理系統,具有輕量、自我調校和極少管理需求的特點。它支援多平台,並提供高效能和參照完整性。

    • IBLite:免費的SQL引擎,資料函式庫檔案大小限制在100 MB以內,缺乏加密功能和Change Views支援。
    • IBToGo:商業版的嵌入式InterBase,無資料函式庫大小限制,並提供強大的加密功能。
  2. SQLite:一個屬於公共領域的關聯式資料函式庫引擎,已被整合到iOS和Android作業系統中。使用SQLite無需額外佈署資料函式庫引擎,因為應用程式可以在執行時動態建立資料函式庫和其結構。

使用FireDAC存取資料函式庫

FireDAC是Delphi中一個強大的資料存取函式庫,支援多種不同的資料函式庫引擎。對於本範例應用程式,我們將使用SQLite作為資料函式庫引擎,並透過FireDAC進行資料存取。

設定FireDAC連線到SQLite

  1. TFDConnection元件拖曳到資料模組上,並將其Name屬性更改為FDConnToDos
  2. 雙擊連線元件以顯示FireDAC Connection Editor視窗。選擇SQLite作為Driver ID,並輸入資料函式庫檔案的名稱。

資料表設計

我們的ToDo List應用程式將使用一個名為ToDos的資料表,該表包含以下欄位:

  • Id:整數型別的主鍵。
  • TitleCategory:文字欄位。

新增資料存取層

透過以下步驟將資料存取層新增至我們的範例應用程式:

  1. 設定FDConnToDos連線元件以連線到SQLite資料函式庫。
  2. 使用查詢元件連線到資料函式庫連線,以執行SQL命令讀寫資料。

程式碼範例與解說

// 建立TFDConnection連線元件
FDConnToDos := TFDConnection.Create(nil);
// 設定連線引數
FDConnToDos.DriverName := 'SQLite';
FDConnToDos.Params.Database := 'ToDos.db';
FDConnToDos.Params.UserMode := dmManual;
// 開啟連線
FDConnToDos.Open;

內容解密:

  • 上述程式碼建立了一個名為FDConnToDosTFDConnection例項,用於連線到SQLite資料函式庫。
  • 設定DriverName'SQLite'以指定使用SQLite驅動程式。
  • 透過Params.Database屬性指定資料函式庫檔案名稱為'ToDos.db'
  • Params.UserMode設定為dmManual以手動管理連線。
  • 最後呼叫Open方法開啟資料函式庫連線。

在行動裝置上使用FireDAC存取SQLite資料函式庫

建立SQLite資料函式庫連線

要在行動裝置上使用SQLite資料函式庫,首先需要在Windows機器上建立一個SQLite資料函式庫檔案。為此,請在C:\Users\Public\Documents\目錄下建立一個名為ToDos.db的資料函式庫檔案。

  1. 無需輸入使用者名稱和密碼,所有預設引數值均可保留。預設的OpenMode引數設定為CreateUTF8,這意味著資料函式庫檔案將在首次嘗試連線時自動建立。
  2. 點選Test按鈕測試連線,如果連線成功,將在C:\Users\Public\Documents\資料夾中建立一個新的空SQLite資料函式庫檔案。

使用FireDAC Connection Editor

FireDAC Connection Editor是一個非常方便的工具。在第二個標籤頁中,有不同的選項可以控制FireDAC的工作方式。第三個標籤頁提供了有關資料函式庫連線的各種資訊。最後一個標籤頁稱為SQL Script,可以用於對已連線的資料函式庫執行任意SQL陳述式。

SQLite具有一個很好的SQL結構,CREATE TABLE IF NOT EXIST...,可以用於在開啟資料函式庫後直接建立資料函式庫表格。

建立ToDos資料函式庫表格

  1. 點選SQL Script標籤頁,並輸入以下程式碼以建立ToDos資料函式庫表格:
CREATE TABLE IF NOT EXISTS ToDos (
  Id INTEGER NOT NULL PRIMARY KEY,
  Title TEXT,
  Category TEXT)
  1. 點選綠色箭頭按鈕執行查詢,如果查詢執行成功,將建立ToDos資料函式庫表格。

內容解密:

  • CREATE TABLE IF NOT EXISTS ToDos:如果ToDos表格不存在,則建立它。
  • Id INTEGER NOT NULL PRIMARY KEY:建立一個名為Id的整數主鍵欄位,該欄位不能為空。
  • Title TEXTCategory TEXT:建立兩個名為Title和Category的文字欄位。

將資料函式庫佈署到行動裝置

有兩種方法可以將資料函式庫佈署到行動裝置。可以使用Deployment Manager並將現有的資料函式庫檔案新增到要佈署的檔案清單中。另一種更簡單的方法是動態建立資料函式庫檔案和資料函式庫表格。

初始化資料函式庫連線

  1. 將連線元件的LoginPrompt屬性設定為False。
  2. OnBeforeConnect事件處理程式中,指定資料函式庫檔案的位置和名稱。
procedure TDMToDo.FDConnToDosBeforeConnect(Sender: Tobject);
begin
  if IsMobilePlatform then
    FDConnToDos.Params.Values['Database'] :=
      TPath.Combine(TPath.GetDocumentsPath, 'ToDos.db');
end;

內容解密:

  • IsMobilePlatform:檢查是否在行動裝置上執行。
  • TPath.Combine(TPath.GetDocumentsPath, 'ToDos.db'):取得行動裝置上的檔案目錄,並將資料函式庫檔案名稱與其結合。
  1. OnAfterConnect事件處理程式中,建立ToDos表格如果它不存在。
procedure TDMToDo.FDConnToDosAfterConnect(Sender: Tobject);
const
  SCreateTableSQL = 'CREATE TABLE IF NOT EXISTS ToDos ('
    + 'Id INTEGER NOT NULL PRIMARY KEY,'
    + 'Title TEXT, Category TEXT)';
begin
  if IsMobilePlatform then
    FDConnToDos.ExecSQL(SCreateTableSQL);
end;

內容解密:

  • SCreateTableSQL:定義建立ToDos表格的SQL陳述式。
  • FDConnToDos.ExecSQL(SCreateTableSQL):執行SQL陳述式以建立ToDos表格。

實作IToDoData介面

  1. IToDoData新增到TDMToDo類別宣告中,並複製介面方法的簽章到資料模組類別的公開區段。
  2. 按下Ctrl + Shift + C鍵組合以呼叫類別完成並產生空的方法實作。

新增TFDQuery元件

  1. 將六個TFDQuery元件拖曳到表單上,並分別將它們命名為FdqToDoMaxId、FdqToDoInsert、FdqToDoSelect、FdqToDoUpdate、FdqToDoDelete和FdqToDoSelectAll。

FireDAC元件在資料模組上的組態

@startuml
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle

title 行動應用程式嵌入式資料函式庫實作

package "資料庫架構" {
    package "應用層" {
        component [連線池] as pool
        component [ORM 框架] as orm
    }

    package "資料庫引擎" {
        component [查詢解析器] as parser
        component [優化器] as optimizer
        component [執行引擎] as executor
    }

    package "儲存層" {
        database [主資料庫] as master
        database [讀取副本] as replica
        database [快取層] as cache
    }
}

pool --> orm : 管理連線
orm --> parser : SQL 查詢
parser --> optimizer : 解析樹
optimizer --> executor : 執行計畫
executor --> master : 寫入操作
executor --> replica : 讀取操作
cache --> executor : 快取命中

master --> replica : 資料同步

note right of cache
  Redis/Memcached
  減少資料庫負載
end note

@enduml

圖表翻譯: 此圖示展示了TDMToDo資料模組與其上的FireDAC元件之間的關係,包括連線元件和多個查詢元件。

實作TDMToDo類別的方法

  1. 在FdqToDoMaxId查詢元件上雙擊,以顯示查詢編輯器視窗,並輸入查詢的SQL程式碼。
type
  TDMToDo = class(TDataModule, IToDoData)
    FdconnToDos: TFDConnection;
    FdqToDoInsert: TFDQuery;
    FdqToDoSelect: TFDQuery;
    FdqToDoUpdate: TFDQuery;
    FdqToDoDelete: TFDQuery;
    FdqToDoSelectAll: TFDQuery;
    FdqToDoMaxId: TFDQuery;
    FDGUIxWaitCursor1: TFDGUIxWaitCursor;
    procedure FdconnToDosBeforeConnect(Sender: TObject);
    procedure FdconnToDosAfterConnect(Sender: TObject);
  private
    function IsMobilePlatform: Boolean;
    function GetNewId: Integer;
  public
    // IToDoData
    function ToDoCreate(AValue: TToDo): Integer;
    function ToDoRead(Id: Integer; out AValue: TToDo): Boolean;
    function ToDoUpdate(AValue: TToDo): Boolean;
    function ToDoDelete(Id: Integer): Boolean;
    procedure ToDoList(AList: TToDos);
  end;

內容解密:

  • TDMToDo類別實作了IToDoData介面,提供了對ToDos資料函式庫表格的CRUD操作。
  • IsMobilePlatform函式檢查是否在行動裝置上執行。
  • GetNewId函式用於取得新的Id值。

本篇文章詳細介紹瞭如何使用FireDAC在行動裝置上存取SQLite資料函式庫,包括建立資料函式庫連線、建立資料函式庫表格、初始化資料函式庫連線以及實作IToDoData介面等步驟。透過這些步驟,開發者可以輕鬆地在行動裝置上使用SQLite資料函式庫,並進行相關的操作。