次の方法で共有


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

サンプルを参照します。 サンプルを参照する

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.cs で、AddSingleton メソッドと 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) ファイルを作成します。 必ず、これらのファイルにも変更を適用してください。