Android での SQLite.NET の使用

Xamarin が推奨する SQLite.NET ライブラリは、Android デバイス上のローカル SQLite データベースのオブジェクトを簡単に格納および取得できる非常に基本的な ORM です。 ORM はオブジェクト リレーショナル マッピングの略で、SQL ステートメントを記述せずにデータベースの "オブジェクト" を保存および取得できる API です。

Xamarin アプリに SQLite.NET ライブラリを含めるには、次の NuGet パッケージをプロジェクトに追加します。

SQLite.NET NuGet package

使用可能な多数のさまざまな SQLite パッケージがあります。必ず、正しいもの (上位の検索結果ではない場合があります) を選択してください。

重要

SQLite.NET は、praeclarum/sqlite-net リポジトリからサポートされているサードパーティ製ライブラリです。

SQLite.NET ライブラリを使用できるようになったら、次の 3 つの手順に従い、それを使ってデータベースにアクセスします。

  1. using ステートメントを追加する – データ アクセスが必要な C# ファイルに次のステートメントを追加します。

    using SQLite;
    
  2. 空のデータベースを作成する – SQLiteConnection クラス コンストラクターにファイル パスを渡すことで、データベース参照を作成できます。 ファイルが既に存在するかどうかを確認する必要はありません。必要に応じて自動的に作成されます。それ以外の場合は、既存のデータベース ファイルが開きます。 dbPath 変数は、このドキュメントで前述した規則に従って決定する必要があります。

    var db = new SQLiteConnection (dbPath);
    
  3. データを保存する – SQLiteConnection オブジェクトを作成すると、次のように CreateTable や Insert などのメソッドを呼び出すことで、データベース コマンドが実行されます。

    db.CreateTable<Stock> ();
    db.Insert (newStock); // after creating the newStock object
    
  4. データを取得する – オブジェクト (またはオブジェクトの一覧) を取得するには、次の構文を使用します。

    var stock = db.Get<Stock>(5); // primary key id of 5
    var stockList = db.Table<Stock>();
    

基本的なデータ アクセスのサンプル

このドキュメントの DataAccess_Basic サンプル コードは、Android で実行するときは次のようになります。 このコードでは、単純な SQLite.NET 操作を実行する方法が示され、結果がアプリケーションのメイン ウィンドウにテキストとして表示されます。

Android

Android SQLite.NET sample

次のコード サンプルは、SQLite.NET ライブラリを使用して基になるデータベース アクセスをカプセル化するデータベース全体の相互作用を示しています。 以下が示されます。

  1. データベース ファイルを作成する

  2. オブジェクトを作成して保存し、データを挿入する

  3. データのクエリ

次の名前空間を含める必要があります。

using SQLite; // from the github SQLite.cs class

最後に、SQLite をプロジェクトに追加する必要があります。 SQLite データベース テーブルは、CREATE TABLE コマンドではなく、クラス (Stock クラス) に属性を追加することによって定義されることに注意してください。

[Table("Items")]
public class Stock {
    [PrimaryKey, AutoIncrement, Column("_id")]
    public int Id { get; set; }
    [MaxLength(8)]
    public string Symbol { get; set; }
}
public static void DoSomeDataAccess () {
       Console.WriteLine ("Creating database, if it doesn't already exist");
   string dbPath = Path.Combine (
        Environment.GetFolderPath (Environment.SpecialFolder.Personal),
        "ormdemo.db3");
   var db = new SQLiteConnection (dbPath);
   db.CreateTable<Stock> ();
   if (db.Table<Stock> ().Count() == 0) {
        // only insert the data if it doesn't already exist
        var newStock = new Stock ();
        newStock.Symbol = "AAPL";
        db.Insert (newStock);
        newStock = new Stock ();
        newStock.Symbol = "GOOG";
        db.Insert (newStock);
        newStock = new Stock ();
        newStock.Symbol = "MSFT";
        db.Insert (newStock);
    }
    Console.WriteLine("Reading data");
    var table = db.Table<Stock> ();
    foreach (var s in table) {
        Console.WriteLine (s.Id + " " + s.Symbol);
    }
}

テーブル名パラメーターを指定せずに [Table] 属性を使用すると、基になるデータベース テーブルの名前がクラスと同じになります (この場合は "Stock")。 実際のテーブル名は、ORM データ アクセス メソッドを使用するのではなく、データベースに対して SQL クエリを直接記述する場合に重要です。 同様に、[Column("_id")] 属性は省略可能であり、存在しない場合、クラスのプロパティと同じ名前のテーブルに列が追加されます。

SQLite 属性

基になるデータベースに格納される方法を制御するためにクラスに適用できる一般的な属性は次のとおりです。

  • [PrimaryKey] – この属性を整数プロパティに適用し、強制的に基になるテーブルの主キーにすることができます。 複合主キーはサポートされていません。

  • [AutoIncrement] この属性により、データベースに挿入された新しいオブジェクトごとに、整数プロパティの値が自動的にインクリメントされます

  • [Column(name)]name パラメーターでは、基になるデータベース列の名前が設定されます。

  • [Table(name)] – クラスを、指定された名前で基になる SQLite テーブルに格納できるものとしてマークします。

  • [MaxLength(value)] – データベースの挿入を試行するときに、テキスト プロパティの長さを制限します。 この属性はデータベースの挿入または更新操作が試行されたときにのみ "チェック" されるため、コードを使用する場合は、オブジェクトを挿入する前にこれを検証する必要があります。

  • [Ignore] – SQLite.NET はこのプロパティを無視します。 これは、データベースに格納できない型を持つプロパティや、SQLite で自動的に解決できないコレクションをモデル化するプロパティに特に便利です。

  • [Unique] – 基になるデータベース列の値が確実に一意になります。

これらの属性のほとんどは省略可能です。 選択および削除クエリをデータに対して効率的に実行できるように、常に整数の主キーを指定する必要があります。

より複雑なクエリ

SQLiteConnection の次のメソッドを使用して、他のデータ操作を実行できます。

  • Insert – データベースに新しいオブジェクトを追加します。

  • Get<T> – 主キーを使用してオブジェクトの取得を試行します。

  • Table<T> – テーブル内のすべてのオブジェクトを返します。

  • Delete – 主キーを使用してオブジェクトを削除します。

  • Query<T> – 多数の行を (オブジェクトとして) 返す SQL クエリを実行します。

  • Execute – (INSERT、UPDATE、DELETE 命令など) SQL から行が戻ることが予想されない場合は、このメソッド (Query ではなく) を使用します。

主キーによるオブジェクトの取得

SQLite.Net では、主キーに基づいて単一のオブジェクトを取得する Get メソッドが提供されます。

var existingItem = db.Get<Stock>(3);

Linq を使用したオブジェクトの選択

コレクションを返すメソッドでは IEnumerable<T> がサポートされているため、Linq を使用してテーブルの内容をクエリまたは並べ替えることができます。 次のコードは、Linq を使用して文字 "A" で始まるすべてのエントリをフィルターで除外する例を示しています。

var apple = from s in db.Table<Stock>()
    where s.Symbol.StartsWith ("A")
    select s;
Console.WriteLine ("-> " + apple.FirstOrDefault ().Symbol);

SQL を使用したオブジェクトの選択

SQLite.Net ではデータへのオブジェクト ベースのアクセスを提供できますが、Linq で許可されているよりも複雑なクエリを実行する必要がある場合があります (または、より高速なパフォーマンスが必要になる場合があります)。 次に示すように、Query メソッドで SQL コマンドを使用できます。

var stocksStartingWithA = db.Query<Stock>("SELECT * FROM Items WHERE Symbol = ?", "A");
foreach (var s in stocksStartingWithA) {
    Console.WriteLine ("a " + s.Symbol);
}

Note

SQL ステートメントを直接記述するときは、クラスとその属性から生成されたデータベース内のテーブルと列の名前に対する依存関係を作成します。 コードでこれらの名前を変更する場合は、手動で記述された SQL ステートメントを忘れずに更新する必要があります。

オブジェクトの削除

次に示すように、行を削除するために主キーが使用されます。

var rowcount = db.Delete<Stock>(someStock.Id); // Id is the primary key

rowcount を調べ、影響を受けた (この場合は削除された) 行の数を確認できます。

複数のスレッドでの SQLite.NET の使用

SQLite では、"シングルスレッド"、"マルチスレッド"、"シリアル化" の 3 つの異なるスレッド モードがサポートされています。 制限なしで複数のスレッドからデータベースにアクセスする場合は、シリアル化スレッド モードを使用するように SQLite を構成できます。 このモードは、アプリケーションで早い段階 (たとえば、OnCreate メソッドの先頭) に設定することが重要です。

スレッド モードを変更するには、SqliteConnection.SetConfig を呼び出します。 たとえば、次のコード行では、シリアル化モードの SQLite を構成します。

using using Mono.Data.Sqlite;
...
SqliteConnection.SetConfig(SQLiteConfig.Serialized);

Android バージョンの SQLite には、さらにいくつかの手順を必要とする制限があります。 SqliteConnection.SetConfig の呼び出しで library used incorrectly などの SQLite 例外が生成される場合は、次の回避策を使用する必要があります。

  1. ネイティブ libsqlite.so ライブラリにリンクして、sqlite3_shutdown および sqlite3_initialize API をアプリで使用できるようにします。

    [DllImport("libsqlite.so")]
    internal static extern int sqlite3_shutdown();
    
    [DllImport("libsqlite.so")]
    internal static extern int sqlite3_initialize();
    
  2. OnCreate メソッドの先頭に、次のコードを追加して SQLite をシャットダウンし、シリアル化モード用に構成し、SQLite を再初期化します。

    using using Mono.Data.Sqlite;
    ...
    sqlite3_shutdown();
    SqliteConnection.SetConfig(SQLiteConfig.Serialized);
    sqlite3_initialize();
    

この回避策は、Mono.Data.Sqlite ライブラリでも機能します。 SQLite とマルチスレッドの詳細については、SQLite と複数のスレッドに関するページを参照してください。