搭配 Xamarin.iOS 使用 ADO.NET

Xamarin 內建支援 iOS 上提供的 SQLite 資料庫,並使用熟悉的 ADO 公開。類似 NET 的語法。 使用這些 API 需要您撰寫由 SQLite 處理的 SQL 語句,例如 CREATE TABLE、 INSERT 和 SELECT 語句。

組件參考

若要透過 ADO.NET 使用存取 SQLite,您必須新增 System.Data 和 Mono.Data.Sqlite 參考 iOS 專案,如下所示(如需 Visual Studio for Mac 和 Visual Studio 中的範例):

以滑鼠右鍵按兩下 [ 參考 > 編輯參考... ],然後按下以選取必要的元件。

關於 Mono.Data.Sqlite

我們將使用 類別 Mono.Data.Sqlite.SqliteConnection 來建立空白資料庫檔案,然後具現化 SqliteCommand 可用來對資料庫執行 SQL 指令的物件。

  1. 建立空白資料庫 - 使用有效的 (即可寫入) 檔案路徑呼叫 CreateFile 方法。 您應該先檢查檔案是否存在,再呼叫此方法,否則會在舊檔案頂端建立新的 (空白) 資料庫,而舊檔案中的數據將會遺失:

    Mono.Data.Sqlite.SqliteConnection.CreateFile (dbPath);

    注意

    變數 dbPath 應根據本檔稍早討論的規則來決定。

  2. 建立資料庫 連線 - 建立 SQLite 資料庫檔案之後,您可以建立連接物件來存取數據。 連接是使用 採用 的 Data Source=file_path連接字串 建構,如下所示:

    var connection = new SqliteConnection ("Data Source=" + dbPath);
    connection.Open();
    // do stuff
    connection.Close();
    

    如先前所述,不應該在不同線程之間重複使用連線。 如有疑問,請視需要建立連線,並在完成時將其關閉;但要注意這樣做的頻率也比需要多。

  3. 建立和執行資料庫命令 - 一旦我們有連接,就可以對其執行任意 SQL 命令。 下列程式代碼顯示正在執行的 CREATE TABLE 語句。

    using (var command = connection.CreateCommand ()) {
        command.CommandText = "CREATE TABLE [Items] ([_id] int, [Symbol] ntext, [Name] ntext);";
        var rowcount = command.ExecuteNonQuery ();
    }
    

直接對資料庫執行 SQL 時,您應該採取一般預防措施,不要提出無效的要求,例如嘗試建立已經存在的數據表。 追蹤資料庫的結構,以免造成 SqliteException,例如“SQLite 錯誤數據表 [Items] 已經存在”。

基本數據存取

在 iOS 上執行時,本檔的DataAccess_Basic 範例程式代碼看起來會像這樣:

iOS ADO.NET sample

下列程式代碼說明如何執行簡單的 SQLite 作業,並將結果顯示為應用程式主視窗中的文字。

您必須包含這些命名空間:

using System;
using System.IO;
using Mono.Data.Sqlite;

下列程式代碼範例顯示整個資料庫互動:

  1. 建立資料庫檔案
  2. 插入一些數據
  3. 查詢資料

這些作業通常會出現在程式代碼的多個位置,例如,當您的應用程式第一次啟動並執行應用程式個別畫面中的數據讀取和寫入時,您可能會建立資料庫檔案和數據表。 在下列範例中,本範例已分組為單一方法:

public static SqliteConnection connection;
public static string DoSomeDataAccess ()
{
    // determine the path for the database file
    string dbPath = Path.Combine (
        Environment.GetFolderPath (Environment.SpecialFolder.Personal),
        "adodemo.db3");

    bool exists = File.Exists (dbPath);

    if (!exists) {
        Console.WriteLine("Creating database");
        // Need to create the database before seeding it with some data
        Mono.Data.Sqlite.SqliteConnection.CreateFile (dbPath);
        connection = new SqliteConnection ("Data Source=" + dbPath);

        var commands = new[] {
            "CREATE TABLE [Items] (_id ntext, Symbol ntext);",
            "INSERT INTO [Items] ([_id], [Symbol]) VALUES ('1', 'AAPL')",
            "INSERT INTO [Items] ([_id], [Symbol]) VALUES ('2', 'GOOG')",
            "INSERT INTO [Items] ([_id], [Symbol]) VALUES ('3', 'MSFT')"
        };
        // Open the database connection and create table with data
        connection.Open ();
        foreach (var command in commands) {
            using (var c = connection.CreateCommand ()) {
                c.CommandText = command;
                var rowcount = c.ExecuteNonQuery ();
                Console.WriteLine("\tExecuted " + command);
            }
        }
    } else {
        Console.WriteLine("Database already exists");
        // Open connection to existing database file
        connection = new SqliteConnection ("Data Source=" + dbPath);
        connection.Open ();
    }

    // query the database to prove data was inserted!
    using (var contents = connection.CreateCommand ()) {
        contents.CommandText = "SELECT [_id], [Symbol] from [Items]";
        var r = contents.ExecuteReader ();
        Console.WriteLine("Reading data");
        while (r.Read ())
            Console.WriteLine("\tKey={0}; Value={1}",
                              r ["_id"].ToString (),
                              r ["Symbol"].ToString ());
    }
    connection.Close ();
}

更複雜的查詢

因為 SQLite 允許對資料執行任意 SQL 命令,因此您可以執行任何您想要的 CREATE、INSERT、UPDATE、DELETE 或 SELECT 語句。 您可以在 Sqlite 網站上閱讀 SQLite 支援的 SQL 命令。 SQL 語句是在 SqliteCommand 物件上使用三種方法之一來執行:

  • ExecuteNonQuery – 通常用於數據表建立或數據插入。 某些作業的傳回值是受影響的數據列數目,否則為 -1。
  • ExecuteReader – 當應該以 傳回 SqlDataReader 數據列的集合時使用。
  • ExecuteScalar – 擷取單一值(例如匯總)。

EXECUTENONQUERY

INSERT、UPDATE 和 DELETE 語句會傳回受影響的數據列數目。 所有其他 SQL 語句都會傳回 -1。

using (var c = connection.CreateCommand ()) {
    c.CommandText = "INSERT INTO [Items] ([_id], [Symbol]) VALUES ('1', 'APPL')";
    var rowcount = c.ExecuteNonQuery (); // rowcount will be 1
}

EXECUTEREADER

下列方法會顯示 SELECT 語句中的 WHERE 子句。 因為程式代碼正在製作完整的 SQL 語句,所以必須小心逸出字串周圍的引號 (') 等保留字元。

public static string MoreComplexQuery ()
{
    var output = "";
    output += "\nComplex query example: ";
    string dbPath = Path.Combine (
        Environment.GetFolderPath (Environment.SpecialFolder.Personal), "ormdemo.db3");

    connection = new SqliteConnection ("Data Source=" + dbPath);
    connection.Open ();
    using (var contents = connection.CreateCommand ()) {
        contents.CommandText = "SELECT * FROM [Items] WHERE Symbol = 'MSFT'";
        var r = contents.ExecuteReader ();
        output += "\nReading data";
        while (r.Read ())
            output += String.Format ("\n\tKey={0}; Value={1}",
                    r ["_id"].ToString (),
                    r ["Symbol"].ToString ());
    }
    connection.Close ();

    return output;
}

ExecuteReader 方法會傳回 SqliteDataReader 物件。 除了範例中顯示的 Read 方法之外,其他有用的屬性還包括:

  • RowsAffected – 受查詢影響的數據列計數。
  • HasRows – 是否傳回任何數據列。

EXECUTESCALAR

針對傳回單一值的SELECT語句,請使用此選項(例如匯總)。

using (var contents = connection.CreateCommand ()) {
    contents.CommandText = "SELECT COUNT(*) FROM [Items] WHERE Symbol <> 'MSFT'";
    var i = contents.ExecuteScalar ();
}

方法 ExecuteScalar 的傳回類型為 object – 您應該根據資料庫查詢來轉換結果。 結果可能是來自 COUNT 查詢的整數,或來自單一數據行 SELECT 查詢的字串。 請注意,這與其他 Execute 方法不同,這些方法會傳回讀取器物件或受影響的數據列數目計數。

Microsoft.Data.Sqlite

有另一個連結庫Microsoft.Data.Sqlite可從 NuGet 安裝,其功能相當於 Mono.Data.Sqlite 並允許相同類型的查詢。

這兩個 連結庫 與一些 Xamarin 特定詳細數據之間有比較。 對於 Xamarin.iOS 應用程式來說,最重要的是,您必須包含初始化呼叫:

// required for Xamarin.iOS
SQLitePCL.Batteries_V2.Init();