.NET MAUI ローカル データベース

Browse sample. サンプルを参照する

SQLite データベース エンジンを使用すると、.NET Multi-platform App UI (.NET MAUI) アプリでデータ オブジェクトを読み込み、共有コードに保存できます。 以下の手順で、SQLite.NET を .NET MAUI アプリに統合し、ローカル データベースに情報を保存および取得できます。

  1. NuGet パッケージをインストールします
  2. 定数を構成します
  3. データベース アクセス クラスを作成します
  4. データにアクセスします
  5. 詳細設定。

この記事では、 sqlite-net-pcl NuGet パッケージを使用して、TODO 項目を格納するテーブルへの SQLite データベース アクセスを提供します。 別の方法として、SQLite 用の軽量 ADO.NET プロバイダーである Microsoft.Data.Sqlite NuGet パッケージを使用することもできます。 Microsoft.Data.Sqlite は、接続、コマンド、データ リーダーなどの機能に共通の ADO.NET 抽象化を実装しています。

SQLite NuGet パッケージをインストールする

NuGet パッケージ マネージャーを使用して sqlite-net-pcl パッケージを検索し、最新バージョンを .NET MAUI アプリ プロジェクトに追加します。

類似した名前を持つ NuGet パッケージが多数あります。 正しいパッケージには、次の属性があります。

  • ID: sqlite-net-pcl
  • 作成者: SQLite-net
  • 所有者: praeclarum
  • NuGet リンク:sqlite-net-pcl

パッケージ名に関係なく、.NET MAUI プロジェクトで sqlite-net-pcl NuGet パッケージを使用します。

重要

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

SQLitePCLRaw.bundle_green をインストールする

sqlite-net-pcl に加えて、各プラットフォームで SQLite を発行する、基になる依存関係を一時的にインストールする必要があります。

  • ID: SQLitePCLRaw.bundle_green
  • バージョン:>= 2.1.0
  • 作成者: Eric Sink
  • 所有者: Eric Sink
  • NuGet リンク:SQLitePCLRaw.bundle_green

アプリ定数を構成する

データベース ファイル名やパスなどの構成データは、アプリに定数として保存できます。 サンプル プロジェクトには、共通の構成データを提供する Constants.cs ファイルが含まれています。

public static class Constants
{
    public const string DatabaseFilename = "TodoSQLite.db3";

    public const SQLite.SQLiteOpenFlags Flags =
        // open the database in read/write mode
        SQLite.SQLiteOpenFlags.ReadWrite |
        // create the database if it doesn't exist
        SQLite.SQLiteOpenFlags.Create |
        // enable multi-threaded database access
        SQLite.SQLiteOpenFlags.SharedCache;

    public static string DatabasePath =>
        Path.Combine(FileSystem.AppDataDirectory, DatabaseFilename);
}

この例では、定数ファイルは、データベース接続の初期化に使用される既定 SQLiteOpenFlag の列挙値を指定します。 SQLiteOpenFlag 列挙型では、これらの値をサポートしている。

  • Create: データベース ファイルが存在しない場合、接続によって自動的に作成されます。
  • FullMutex: シリアル化されたスレッド モードで接続が開きます。
  • NoMutex: 接続はマルチスレッド モードで開かれます。
  • PrivateCache: 接続が有効になっている場合でも、接続は共有キャッシュに関与しません。
  • ReadWrite: 接続によりデータの読み取りと書き込みが行われます。
  • SharedCache: 接続が有効になっている場合、接続は共有キャッシュに関与します。
  • ProtectionComplete: デバイスがロックされている間、ファイルは暗号化され、アクセスできません。
  • ProtectionCompleteUnlessOpen: ファイルは開くまで暗号化されますが、ユーザーがデバイスをロックした場合でもアクセスできます。
  • ProtectionCompleteUntilFirstUserAuthentication: ファイルは、ユーザーがデバイスを再起動してロックを解除するまで暗号化されます。
  • ProtectionNone: データベース ファイルは暗号化されていません。

データベースの使用方法に応じて、異なるフラグを指定する必要がある可能性があります。 SQLiteOpenFlagsについての詳細は、「sqlite.org で新しいデータベース接続を開く」をご覧ください。

データベース アクセス クラスを作成します

データベース ラッパー クラスは、アプリの他の部分からデータアクセス層を抽象化します。 このクラスは、クエリ ロジックを一元化し、データベース初期化の管理を簡素化することにより、アプリの拡張に合わせてデータ操作をリファクタリングまたは拡張しやすくします。 サンプル アプリでは、この目的のために TodoItemDatabase クラスが定義されます。

遅延初期化

TodoItemDatabase では、非同期遅延初期化を使用して、最初にアクセスされるまでデータベースの初期化を遅らせ、クラス内の各メソッドによって呼び出される単純な Init メソッドを使用します。

public class TodoItemDatabase
{
    SQLiteAsyncConnection Database;

    public TodoItemDatabase()
    {
    }

    async Task Init()
    {
        if (Database is not null)
            return;

        Database = new SQLiteAsyncConnection(Constants.DatabasePath, Constants.Flags);
        var result = await Database.CreateTableAsync<TodoItem>();
    }
    ...
}

データ操作メソッド

この TodoItemDatabase クラスには、作成、読み取り、編集、削除の 4 種類のデータ操作のメソッドが組み込まれています。 SQLite.NET ライブラリには、SQL ステートメントを記述せずにオブジェクトを保存および取得できる単純なオブジェクト リレーショナル マップ (ORM) を備えています。

次の例は、サンプル アプリのデータ操作メソッドを示しています。

public class TodoItemDatabase
{
    ...
    public async Task<List<TodoItem>> GetItemsAsync()
    {
        await Init();
        return await Database.Table<TodoItem>().ToListAsync();
    }

    public async Task<List<TodoItem>> GetItemsNotDoneAsync()
    {
        await Init();
        return await Database.Table<TodoItem>().Where(t => t.Done).ToListAsync();

        // SQL queries are also possible
        //return await Database.QueryAsync<TodoItem>("SELECT * FROM [TodoItem] WHERE [Done] = 0");
    }

    public async Task<TodoItem> GetItemAsync(int id)
    {
        await Init();
        return await Database.Table<TodoItem>().Where(i => i.ID == id).FirstOrDefaultAsync();
    }

    public async Task<int> SaveItemAsync(TodoItem item)
    {
        await Init();
        if (item.ID != 0)
            return await Database.UpdateAsync(item);
        else
            return await Database.InsertAsync(item);
    }

    public async Task<int> DeleteItemAsync(TodoItem item)
    {
        await Init();
        return await Database.DeleteAsync(item);
    }
}

データにアクセスする

依存関係の挿入を使用している場合は、アプリ全体で使用できるシングルトンとして TodoItemDatabase クラスを登録できます。 たとえば、MauiProgram.csAddSingleton メソッドと AddTransient メソッドで、IServiceCollection オブジェクトのサービスとしてページとデータベースアクセスクラスを登録できます

builder.Services.AddSingleton<TodoListPage>();
builder.Services.AddTransient<TodoItemPage>();

builder.Services.AddSingleton<TodoItemDatabase>();

これらのサービスは、クラス コンストラクターに自動的に組み込まれ、アクセスすることができます。

TodoItemDatabase database;

public TodoItemPage(TodoItemDatabase todoItemDatabase)
{
    InitializeComponent();
    database = todoItemDatabase;
}

async void OnSaveClicked(object sender, EventArgs e)
{
    if (string.IsNullOrWhiteSpace(Item.Name))
    {
        await DisplayAlert("Name Required", "Please enter a name for the todo item.", "OK");
        return;
    }

    await database.SaveItemAsync(Item);
    await Shell.Current.GoToAsync("..");
}

または、データベース アクセス クラスの新しいインスタンスを作成することもできます。

TodoItemDatabase database;

public TodoItemPage()
{
    InitializeComponent();
    database = new TodoItemDatabase();
}

.NET MAUI アプリでの依存関係の挿入の詳細については、「依存関係の挿入」を参照してください

詳細な構成

SQLite は、この記事とサンプル アプリで説明されている以上の機能を備えた堅牢な API を提供しています。 次のセクションでは、スケーラビリティに重要な機能について説明します。

詳細は、 sqlite. org に掲載されている SQLite ドキュメントをご覧ください。

先書きログ

既定では、SQLite は従来のロールバック ジャーナルを使用します。 変更されていないデータベース コンテンツのコピーが別のロールバック ファイルに書き込まれ、その後、変更がデータベース ファイルに直接書き込まれます。 COMMIT は、ロールバック ジャーナルが削除されるときに発生します。

先書きログ (WAL) は、まず別の WAL ファイルに変更を書き込みます。 WAL モードでは、COMMIT は WAL ファイルに追加される特別なレコードであり、これにより、1 つの WAL ファイルで複数のトランザクションが実行できます。 WAL ファイルは、チェックポイントと呼ばれる特殊な操作でデータベース ファイルにマージされます。

リーダーとライターが互いを妨害せず、読み取り操作と書き込み操作を同時に実行できるため、ローカル データベースでは WAL の方が高速になります。 ただし、WAL モードでは、ページ サイズの変更を許可せず、データベースにファイルの関連付けを追加し、追加のチェックポイント操作を追加します。

SQLite.NET で WAL を有効にするには、SQLiteAsyncConnection インスタンスで EnableWriteAheadLoggingAsync メソッドを呼び出します。

await Database.EnableWriteAheadLoggingAsync();

詳細については、sqlite.org に掲載されている「SQLite 先書きログ」をご覧ください。

データベースをコピーする

次のように、SQLite データベースのコピーが必要となる場合もいくつかあります:

  • データベースはアプリケーションに含まれていますが、モバイル デバイス上の書き込み可能ストレージにコピーまたは移行する必要があります。
  • データベースのバックアップまたはコピーを作成する必要があります。
  • データベース ファイルのバージョン管理、移動、または名前変更が必要です。

一般に、データベース ファイルの移動、名前変更、またはコピーは、他のファイル タイプと同じプロセスですが、いくつかの追加の考慮事項があります。

  • データベースファイルを移す前に、すべてのデータベース接続を切断する必要があります。
  • 先書きログを使用する場合、SQLite は共有メモリ アクセス (.shm) ファイルと (先書きログ) (.wal) ファイルを作成します。 これらのファイルにも変更を適用します。