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資料函式庫,並進行相關的操作。