.NET8でSQLiteをデータベースとして利用するアプリケーション構築の手順を整理します。ここでは基本的なCRUD(Create/Read/Update/Delete)を実現するアプリケーションを作ってみます。
| 項目 | バージョン |
|---|---|
| OS | Windows11 Pro |
| SQLite | 3.43.1 |
| Visual Studio 2022 Community | 17.11.1 |
| 使用言語 | C# |
■プロジェクト作成
Visual Studio 2022でプロジェクトを作成します。Visual StudioやSQLiteデータベースは既にインストールされている前提とし、一般的な操作(プロジェクト作成、ビルド、デバッグ実行は割愛)で進めます。
新規作成 > プロジェクト からプロジェクトを作成しますが、種類が多くて迷ってしまいます(泣)。今回はGUIを用いた.NET8のアプリケーションとしたいので、「Windowsフォームアプリ」を選択します。利用する言語やプロジェクトの携帯(Web、デスクトップ、モバイル・・etc)を選択するとある程度絞り込みができます。注意として「.NET Framework」の記載がないものを選択ください。.NET Frameworkはクロスプラットフォームの.NET8とは異なるものになります!)

プロジェクトの保存先や名前を決めて「次へ」進みます。

.NET8が選択されていることを確認して「作成」をクリック。

少しするとプロジェクトが作成され、GUIのフォーム画面が開いた状態となります。

この時点でまず1回ビルドして正常に完了することを確認しておきましょう。
1>------ すべてのリビルド開始: プロジェクト:crudapp, 構成: Debug Any CPU ------
C:\tmp\crudapp\crudapp\crudapp\crudapp.csproj を復元しました (3 ミリ秒)。
1>crudapp -> C:\tmp\crudapp\crudapp\crudapp\bin\Debug\net8.0-windows\crudapp.dll
========== すべて再構築: 1 正常終了、0 失敗、0 スキップ ==========
=========== リビルド は 21:18 で完了し、03.925 秒 掛かりました ==========
■NuGetパッケージの追加
今回SQLiteをデータベースに用いるにあたり、EntityFrameworkと呼ばれるORM(Object Relational Mapper)を用いたいと思います。NuGetパッケージの追加を下記の通りの手順で行います。
プロジェクト > NuGetパッケージの管理

NuGetパッケージマネージャーの画面が開いたら、「参照」タブから「entity framework」と入力し、パッケージを検索します。「Microsoft.EntityFrameworkCore」が見つかったら、画面右の「インストール」ボタンからインストールを行います。インストールする際のバージョンは「最新の安定板」を基本選べばOKです。

ソリューションに変更が加わることの確認とライセンスの同意画面が表示されるのでそれぞれ、「適用」、「同意する」を選択します。(他のパッケージ選択時も同様に表示されます)

ライセンスの同意を実行。

インストールが正常に完了すると「インストール済」に表示されます。

同じ手順で、下記のパッケージを導入します。
| 検索時の名称 | 対象パッケージ |
|---|---|
| entity framework tools | Microsoft.EntityFrameworkCore.Tools |
| entity framework sqlite | Microsoft.EntityFrameworkCore.Sqlite |
| configuration | Microsoft.Extensions.Configuration |
| configuration json | Microsoft.Extensions.Configuration.Json |
最終的に以下のような感じになっていると思います。

この段階でまたビルドを通しておきます。
■EntityFrameworkを用いたCRUD処理の実装
EntityFrameworkでCRUD処理を実装するにあたり、大きな流れとして「コードファースト」と「データベースファースト」に分けられます。コードファーストはデータベースに保存するモデル(クラス)を先に定義しそこからデータベースのテーブル定義を作成する形です。一方、データベースファーストは既存のデータベース、テーブルがある状態で逆にモデル(クラス)を定義する方法です。
ここでは新規の環境向けに構築する想定でコードファーストな方法を採用します。
ここからの手順としては、以下のようになります。
- モデルクラスの定義
- データベースコンテキストクラスの定義
- データベース接続設定を設定ファイルに定義
- マイグレーションの実施(コードファーストのモデルをデータベース側に反映させる)
- プログラム(CRUD処理)の実装
- 動作確認
▼モデル(クラス)の定義
いわゆるシンプルなデータクラスを定義し、このクラスがデータベーステーブルと紐づく(1対1で対応する)形とします。
必須ではないですが分かりやすいようにプロジェクト内に「Models」フォルダを作り、モデルクラスはここにまとめることにします。

追加 > 新しい項目 から「クラス」を選択し、名称を「User.cs」とし追加をします。

Modelsフォルダ配下に「User.cs」が作成されたら、以下の内容で修正をします。

3つの項目を持ったクラスとします。(Id、名前、年齢)
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace crudapp.Models
{
public class User
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public long Id { get; set; }
public string? Name { get; set; }
public int Age { get; set; }
}
}
着目するのは、データベースのキー項目にしたい「Id」の「Key」属性と「DatabaseGenerated(DatabaseGeneratedOption.Identity)」です。Keyはその名の通り、キー項目を示します。(ちなみにEntityFrameworkでは、「Id」や「モデル名」+「Id」の名称を自動的にキー項目としてみなしてくれるようではあります)
「DatabaseGenerated(DatabaseGeneratedOption.Identity」はこの項目がデータベース側の自動生成処理に任せることを示します。今回はId項目でしたのでIdをデータベース側で自動付番させるために設定しています。
▼データベースコンテキストクラスの定義
次にモデルクラスとデータベース側をつなぐデータベースコンテキストクラスを作成します。
Userモデルの追加時同様に、Modelsフォルダにクラス:CRUDDbContext.csを作成し、ソースを編集します。

今回は「DbContext」というクラスを継承したクラスを定義し、その中でDbSetにUser型のリストを定義します。今回、Sqliteデータベースへの接続パス設定をappsettings.jsonファイルに保存するのでその設定ファイルからデータベースファイルのありかを取得する処理をOnConfiguringメソッドに実装します。
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace crudapp.Models
{
public partial class CRUDDbContext : DbContext
{
public DbSet<User> Users { get; set; } = default!;
public CRUDDbContext() { }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
//base.OnConfiguring(optionsBuilder);
var confBuilder = new ConfigurationBuilder();
confBuilder.AddJsonFile(path: Path.Combine(Directory.GetCurrentDirectory(), "appsettings.json"));
var conf = confBuilder.Build();
optionsBuilder.UseSqlite(conf.GetConnectionString("CRUDDbContext"));
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
OnModelCreatingPartial(modelBuilder);
}
partial void OnModelCreatingPartial(ModelBuilder modelBuilder);
}
}
▼データベース接続設定を設定ファイルに定義
プロジェクト内に「appsettings.json」という設定ファイルを作成します。追加 > 新しい項目 から「テキストファイル」を選択し、名称を入力し保存をします。

中身は以下のような形で記載します。この設定だと、アプリケーションのカレントパス(同じフォルダ)に「crudapp.db」が存在する前提となります。
{
"ConnectionStrings": {
"CRUDDbContext": "Data Source=crudapp.db;"
}
}
▼マイグレーションの実施
ここまできたら、データベース側にモデルの定義を反映ができる状態となりました。ここからは「パッケージマネージャーコンソール」から実行をします。画面下部に下記のような表示がなければ、表示 > その他のウィンドウ > パッケージマネージャーコンソール から開いておきます。

以下のコマンドを実行し、モデルのコードからデータベースへ反映させるためのコードをVisual Studioに自動生成させます。
add-migration Initial -outputdir Data\Migrations
問題なく処理されれば、以下のような表示「Build succeeded.」になっているはずです。

「-outputdir」オプションでData¥Migrationsという階層化したフォルダに出力するように指定したのでこのような結果になっています。(フォルダ構成はこの構成でないといけないわけではありません)

詳細は解説しませんが、マイグレーション(移行)を行うためのテーブル定義をモデルクラスの定義やデータベースプロバイダ(今回はSQLite)により決定されたコードが下記のようになっています。(必要であればこのソースを修正も可能)
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace crudapp.Data.Migrations
{
/// <inheritdoc />
public partial class Initial : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "Users",
columns: table => new
{
Id = table.Column<long>(type: "INTEGER", nullable: false)
.Annotation("Sqlite:Autoincrement", true),
Name = table.Column<string>(type: "TEXT", nullable: true),
Age = table.Column<int>(type: "INTEGER", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Users", x => x.Id);
});
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "Users");
}
}
}
定義ができたので次にデータベース側に反映を行います。再びパッケージマネージャーコンソールから実行します。
update-database
「Applying migration 先ほど確認したマイグレーションファイル名」が出力され、「Done.」と出ればOKです。

テーブルが本当に確認されたことを確認してみましょう。今回はSQLite3ですので、Sqliteコマンドラインからテーブル定義を確認します。(テーブルを作っただけなのでデータは当然ありません)
ちょっと見づらいですが、赤枠が実行したコマンドで、黄色枠がそのコマンドの結果表示です。きちんとテーブルが生成されているのがわかります。

ちなみに上記のcrudapp.dbの出力先は「C:\tmp\crudapp\crudapp\crudapp\crudapp.db」となっています(Visual Studio プロジェクトのカレントフォルダ内です)。
▼プログラム(CRUD処理)の実装
ここからは.NET8におけるEntityFrameworkを用いたプログラミングです。エッセンスだけを記載したいので極力シンプルにしています。画面の「Add New User」ボタンを押下したら、ユーザを作成しその結果を「〇人目のユーザ:ID 名前 ×歳」としてダイアログに表示するつくりとします。名前はtanaka taroにIDをつけた形とします。

ボタンクリックイベント(button1_Click)含むForm1.csのソース全体は下記のとおりです。
using crudapp.Models;
using Microsoft.EntityFrameworkCore;
namespace crudapp
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
CRUDDbContext ctxt = new CRUDDbContext();
int i = ctxt.Users.Count();
User u = new User();
u.Name = String.Format("tanaka taro{0}", (i + 1));
u.Age = new Random().Next(100);
ctxt.Users.Add(u);
if (ctxt.SaveChanges() > 0)
{
User created = ctxt.Users.First(u => u.Id == (i + 1));
MessageBox.Show(String.Format("{0}人目のユーザ:{1} {2} {3}歳",
created.Id, created.Id, created.Name, created.Age), "登録完了", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
else
{
MessageBox.Show("登録エラー", "登録エラー", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
}
▼動作確認
実際に実行して確認しましょう。VisualStudioでデバッグ動作確認の前に、「appsettings.json」と「crudapp.db」ファイルをbin\Debug\net8.0-windows配下にコピーしておくことを忘れないようにしてください(設定ファイル、DBファイルともに検索がExeファイルのカレントフォルダとなっているためです)。

プログラムをデバッグ実行し、1人目を作成すると以下の表示がでました。(年齢はランダムです)

2人目の結果です。

最後にデータベースを確認して保存されていることを確認しておきます。bin\Debug\net8.0-windows配下のcrudapp.dbへ接続して確認します。アプリの画面で見た通りのデータが保存されていることが確認できました。

CRUD操作のうち、Createのみ実装しました。他の操作(Read/Update/Delete)は今回割愛します。
コメントを残す