SQLite は、Windows アプリにデータをローカルに格納するための信頼性の高い軽量のデータベース ソリューションを提供します。 個別のサーバー インストールと複雑な構成を必要とする従来のデータベース システムとは異なり、SQLite はアプリケーション プロセス内で完全に実行され、ユーザーのデバイス上の 1 つのファイルにデータを格納します。
このチュートリアルでは、Microsoft の推奨されるデータ アクセス ライブラリを使用して、SQLite を WinUI アプリケーションに統合する方法について説明します。 一般的な脆弱性から保護するためのセキュリティのベスト プラクティスに従いながら、データベースの設定、テーブルの作成、基本的なデータ操作の実装について学習します。
作業内容
このチュートリアルでは、次の方法について説明します。
- Microsoft.Data.SQLite ライブラリで SQLite を使用するようにWindows アプリを構成する
- ローカル データベースを作成して初期化する
- セキュリティで保護されたデータの挿入と取得の方法を実装する
- データを操作するためのシンプルなユーザー インターフェイスを構築する
[前提条件]
このチュートリアルを完了するには、次のものが必要です。
- Visual Studio 2022 以降で WinUI アプリケーション開発 ワークロードを使用する
- C# と XAML に関する基本的な知識
- データベースの基本的な概念の理解
このアプローチで提供される主な改善点
Windows アプリでローカル データ ストレージに SQLite を使用すると、次のような利点があります。
- デプロイの簡略化: 個別のデータベース サーバーのインストールは必要ありません
- セキュリティ強化: データはユーザーのデバイス上でローカルのまま
- パフォーマンスの向上: 直接ファイル アクセスにより、ネットワーク待ち時間を排除
- 複雑さの軽減: 単一ファイル データベースを使用すると、バックアップと移行が簡略化されます
学習する手法は、単純な設定ストレージから複雑なデータ管理シナリオまで、構造化データをローカルに格納する必要がある任意のWindows アプリに適用されます。
ヒント
AI アシスタンスを使用して 、SQLite での SQL インジェクション攻撃を回避できます。
ローカル ストレージ用の SQLite の利点
✔️ SQLite は軽量で自己完結型です。 その他の依存関係がないコード ライブラリです。 構成する必要がありません。
✔️ データベース サーバーはありません。 クライアントとサーバーは、同じプロセスで実行されます。
✔️ SQLite はパブリック ドメインにあるため、アプリで自由に使用して配布できます。
✔️ SQLite はプラットフォームやアーキテクチャにかかわらず動作します。
SQLite について詳しくは、こちらをご覧ください。
アブストラクション レイヤーを選択する
Microsoft によってビルドされた Entity Framework Core またはオープンソースの SQLite ライブラリを使用することをお勧めします。
Entity Framework Core
Entity Framework (EF) は、ドメイン固有のオブジェクトを使ってリレーショナル データを操作できる、オブジェクト リレーショナル マッパーです。 既にこのフレームワークを使用して他の.NET アプリのデータを操作している場合は、WinUI アプリで同じコードを使用でき、connection stringに対する適切な変更を処理できます。
試してみるには、「EF Core の概要」を参照してください。
SQLite ライブラリ
Microsoft.Data.Sqlite ライブラリでは、System.Data.Common 名前空間内にインターフェイスを実装しています。 Microsoft では、これらの実装をアクティブに保守しています。これらの実装によって、低レベルのネイティブ SQLite API に関する直感的なラッパーを提供します。
このガイドの残りの部分では、このライブラリの使用について説明します。
Microsoft.Data.SQLite ライブラリを使用するようにソリューションを設定する
基本的な WinUI プロジェクトから始めて、SQLite NuGet パッケージをインストールします。 最初 の WinUI プロジェクトを作成 する方法については、「WinUI アプリの作成」を参照してください。
サポートされているすべてのバージョンのWindowsは SQLite をサポートしているため、アプリで SQLite ライブラリをパッケージ化する必要はありません。 代わりに、アプリは、Windowsにインストールされている SQLite のバージョンを使用できます。 これにより、次のような利点が得られます。
✔️ SQLite バイナリをダウンロードして、アプリケーションの一部としてパッケージ化する必要がないため、アプリケーションのサイズが小さくなります。
✔️ SQLite のバグやセキュリティの脆弱性に対する重要な修正プログラムが公開された場合でも、アプリの新しいバージョンをユーザーに勧める必要がありません。 SQLite のWindows バージョンは、SQLite.org と連携して Microsoft によって管理されています。
✔️ SQLite の SDK バージョンが既にメモリに読み込まれている可能性が高いため、アプリの読み込み時間が高速になる可能性があります。
まず、DataAccess という名前のプロジェクトにクラスを追加します。 データ アクセス ロジックを他のクライアント コードと共有する場合は、.NET クラス ライブラリ プロジェクトを使用してデータ アクセス コードを含めることができますが、この例では使用しません。
ソリューションを右クリックし、 [ソリューションの NuGet パッケージの管理] をクリックします。
この時点で 2 つの選択肢があります。 Windowsに含まれている SQLite のバージョンを使用することも、特定のバージョンの SQLite を使用する何らかの理由がある場合は、SQLite ライブラリをパッケージに含めることができます。 Windowsに含まれている SQLite のバージョンを使用します。
[参照] タブを選択し、Microsoft.Data.SQLite パッケージを検索して、最新の安定バージョンをインストールします。
SQLite データベースのデータの追加と取得
以下の作業を行います。
1️⃣ データ アクセス クラスを準備します。
2️⃣ SQLite データベースを初期化します。
3️⃣ SQLite データベースにデータを挿入します。
4️⃣ SQLite データベースからデータを取得します。
5️⃣ 基本的なユーザー インターフェイスを追加します。
データ アクセス クラスを準備する
プロジェクトで DataAccess クラスを開き、そのクラスを静的に設定します。
注意
この例ではデータ アクセス コードを静的クラスに配置しますが、これは設計上の選択肢であり、完全に省略可能です。
public static class DataAccess
{
}
このファイルの先頭に、次の using ステートメントを追加します。
using Microsoft.Data.Sqlite;
using System.Collections.Generic;
SQLite データベースを初期化する
DataAccess クラスに、SQLite データベースを初期化するメソッドを追加します。
public async static void InitializeDatabase()
{
await ApplicationData.Current.LocalFolder
.CreateFileAsync("sqliteSample.db", CreationCollisionOption.OpenIfExists);
string dbpath = Path.Combine(ApplicationData.Current.LocalFolder.Path,
"sqliteSample.db");
using (var db = new SqliteConnection($"Filename={dbpath}"))
{
db.Open();
string tableCommand = "CREATE TABLE IF NOT " +
"EXISTS MyTable (Primary_Key INTEGER PRIMARY KEY, " +
"Text_Entry NVARCHAR(2048) NULL)";
var createTable = new SqliteCommand(tableCommand, db);
createTable.ExecuteReader();
}
}
注意
ApplicationData メンバーを使用する上記のコードは、アプリ コンテナーで実行されているパッケージ アプリでのみ機能します。 他のすべてのWindows アプリは、ApplicationData クラスを介して メンバーにアクセスする必要があります。
このコードは、SQLite データベースを作成し、アプリケーションのローカル データ ストアに保存します。
この例では、データベースに sqlliteSample.db という名前を付けますが、インスタンス化するすべての SqliteConnection オブジェクトでその名前を使用する限り、任意の名前を使用することができます。 実稼働アプリケーションでは、データベース ファイル名などの接続情報は、ハードコーディングするのではなく、アプリ構成に格納する必要があります (
プロジェクトの App.xaml.cs ファイルのコンストラクターで、InitializeDatabase クラスの DataAccess メソッドを呼び出します。 これにより、アプリが起動するたびにデータベースが作成されるか、開かれます。
public App()
{
this.InitializeComponent();
DataAccess.InitializeDatabase();
}
SQLite データベースにデータを挿入する
DataAccess クラスに、SQLite データベースにデータを挿入するメソッドを追加します。 このコードでは、クエリでパラメーターを使用して SQL インジェクション攻撃を防ぎます。
public static void AddData(string inputText)
{
string dbpath = Path.Combine(ApplicationData.Current.LocalFolder.Path,
"sqliteSample.db");
using (var db = new SqliteConnection($"Filename={dbpath}"))
{
db.Open();
var insertCommand = new SqliteCommand();
insertCommand.Connection = db;
// Use parameterized query to prevent SQL injection attacks
insertCommand.CommandText = "INSERT INTO MyTable VALUES (NULL, @Entry);";
insertCommand.Parameters.AddWithValue("@Entry", inputText);
insertCommand.ExecuteReader();
}
}
SQLite データベースからデータを取得する
SQLite データベースの表からデータのすべての行を取得するメソッドを追加します。
public static List<string> GetData()
{
var entries = new List<string>();
string dbpath = Path.Combine(ApplicationData.Current.LocalFolder.Path,
"sqliteSample.db");
using (var db = new SqliteConnection($"Filename={dbpath}"))
{
db.Open();
var selectCommand = new SqliteCommand
("SELECT Text_Entry from MyTable", db);
SqliteDataReader query = selectCommand.ExecuteReader();
while (query.Read())
{
entries.Add(query.GetString(0));
}
}
return entries;
}
Read メソッドは、返されるデータの行を次に進めます。 このメソッドでは、残りの行がある場合は true を返し、ない場合は false を返します。
GetString メソッドは、指定された列の値を文字列として返します。 このメソッドでは、必要なデータの 0 から始まる列の序数を表す整数値を受け取ります。 GetDataTime や GetBoolean などの同様のメソッドを使用できます。 列に格納するデータの型に基づいてメソッドを選択します。
この例では 1 つの列のすべてのエントリを選択しているため、序数パラメーターがそれほど重要ではありません。 ただし、クエリに複数の列が含まれる場合は、序数値を使用してデータを取り出す列を取得します。
基本的なユーザー インターフェイスを追加する
プロジェクトの MainWindow.xaml ファイルに、次の XAML を追加します。
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<StackPanel>
<TextBox x:Name="Input_Box"/>
<Button Click="AddData">Add</Button>
<ListView x:Name="Output">
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackPanel>
</Grid>
この基本的なユーザー インターフェイスでは、SQLite データベースに追加する文字列を入力するための TextBox をユーザーに提供します。 この UI の Button を、SQLite データベースからデータを取得して、ListView にそのデータを表示するイベント ハンドラーに接続します。
MainWindow.xaml.cs ファイルに、次のハンドラーを追加します。 これは、UI で Click の Button イベントに関連付けたメソッドです。
private void AddData(object sender, RoutedEventArgs e)
{
DataAccess.AddData(Input_Box.Text);
Output.ItemsSource = DataAccess.GetData();
}
アプリケーションの起動時に既存のデータが読み込まれることを確認する必要もあります。
MainWindow コンストラクターに、GetData() を呼び出すコード行を追加します。
public MainWindow()
{
this.InitializeComponent();
Output.ItemsSource = DataAccess.GetData();
}
これで終了です。 Microsoft.Data.Sqlite を参照して、他に SQLite データベースと連携できるものを確認してください。 Windows アプリでデータを使用する他の方法については、以下のリンクを参照してください。
SQL インジェクション攻撃を回避する
この例のコードでは、パラメーター化されたクエリを使用して SQL インジェクション攻撃を防ぎます。 ユーザー入力を SQL クエリ文字列に連結しないでください。 常にパラメーターを使用します。 SQL インジェクション攻撃の回避に関するその他のヒントについては、Copilotにお問い合わせください。
次のテキストは、Copilotのプロンプトの例を示しています。
Can you provide some best practices to avoid SQL injection attacks when writing SQLite queries in C# code?
Copilotは AI を活用しているため、驚きや間違いが起こりうる可能性があります。 詳細については、Copilot FAQ を参照してください。
関連するコンテンツ
SQL Server データベースにアプリを直接接続する
「
異なるプラットフォームにわたる異なるアプリの間でコードを共有する
デスクトップと UWP 間のコード共有に関するページをご覧ください。
Azure SQL バックエンドを使用してマスター・ディテールページを追加する
Customer Orders Database のサンプルを参照してください。
Windows developer