EfCoreプロバイダー変更


## はじめに

Azure SQL Database ではサブスクリプションごとに１つ無料で SQL Server を作成することができます。学習のため個人開発していたプロジェクトで使用していたのですが、この度完成し次のプロジェクトに取り掛かる際に接続先 DB を SQLite に変更しました。

その際に EFCore の接続先プロパイダーの切り替え作業が発生したため、その手順をまとめます。

:::note info
今回は SQL Server →SQLite で解説しますが、同じ方法で切り替えが可能です。
:::

## 修正方法

以下の順番に対応をしてください。

1. DBContext の修正
2. Nuget から対象プロパイダーの EFCore パッケージを取得
3. `Program.cs`の修正
4. `appsetting.json`の修正

### DBContext の修正

EFCore でプロパイダーを変更する際には大きく分けて２つの方法があります。

1. SQL Server 用とは別に SQLite 用の DBContext を作成して接続する。
2. 既存の Migrations 履歴を削除して新しく Migrations を実施する。

１つ目の方法では SQL Server 用と SQLite 用の DBContext が別々に存在するため段階的な移行も可能です。またこちらの方法では Migration 履歴を残したまま移行することができます。

ただし SQL Server の DBContext をコード上で使用している箇所すべてで使用している DBContext を変更する必要があり、コードの修正量は多くなる傾向があります。

https://learn.microsoft.com/ja-jp/ef/core/managing-schemas/migrations/providers?tabs=vs

２つ目の方法は既存の Migration 履歴をすべて削除もしくはコメント化して初期化する事です。

削除を行う理由は`Add-Migration`時に出力されるコードにプロパイダー固有の記載が含まれているためです。そのままの状態で純粋に接続先を切り替えるだけではマイグレーションの適用時にエラーになってしまいます。

```Csharp:SQLiteでテーブル追加時のMigration履歴
protected override void Up(MigrationBuilder migrationBuilder)
{
    migrationBuilder.CreateTable(
        name: "StudyRecords",
        columns: table => new
        {
            Id = table.Column<int>(type: "INTEGER", nullable: false)
                .Annotation("Sqlite:Autoincrement", true),// SQLite固有の書き方
            Title = table.Column<string>(type: "TEXT", nullable: false),
            StudyTime = table.Column<int>(type: "INTEGER", nullable: false)
        },
        constraints: table =>
        {
            table.PrimaryKey("PK_StudyRecords", x => x.Id);
        });
}
```

上記の例ですと ID 列の設定時に`Sqlite:Autoincrement`というアノテーションを使用しています。この書き方は他のプロパイダー接続時には当然エラーになります。

この方法のメリットは修正範囲が少ない事です。それまで使用していた DBContext の接続先が変わっているためそのまま使用することができます。

ただし履歴の削除もしくはコメント化が必要な点。一度にすべて修正が必要な点がデメリットとして挙げられます。

https://learn.microsoft.com/ja-jp/ef/core/managing-schemas/migrations/managing?tabs=vs#resetting-all-migrations

### Nuget から対象プロパイダーの EFCore パッケージを取得

Nuget より対象プロパイダーのパッケージをインストールしてください。SQLite の場合は`Microsoft.EntityFrameworkCore.Sqlite`です。

この時にすでにインストールされている`Microsoft.EntityFrameworkCore`パッケージのバージョンと同じバージョンをインストールすると安全です。

:::note warn
.net8 のプロジェクトでスキャフォールディングを使用すると Nuget パケージは 8.x.x の物がインストールされます。SQLite 用の EFCore パッケージの最新版(2025/1/18)をインストールすると 9.x.x がインストールされ、この状態で`Update-Database`を実行するとエラーになります。

パッケージのバージョンを合わせると正常に動作しました。
:::

### Program.cs の修正

DBContext を登録している部分のメソッドを`UseSqlServer()`から`UserSqlite()`にします。

```diff_c_sharp
builder.Services.AddDbContextFactory<BlazorApp12Context>(options =>
-    options.UseSqlServer(builder.Configuration.GetConnectionString("SampleAppContext") ?? throw new InvalidOperationException("Connection string 'SampleAppContext' not found.")));
+    options.UseSqlite(builder.Configuration.GetConnectionString("SampleAppContext") ?? throw new InvalidOperationException("Connection string 'SampleAppContext' not found.")));

```

:::note info
DBContext を別々に用意する場合はそれぞれ既存の登録処理の削除は不要です。
:::

### appsetting.json の修正

コネクションストリングを SQLite 用に修正します。

```json
  "ConnectionStrings": {
    "SampleAppContext": "Data Source=SampleAppContext-fac68bf8-83d6-46cb-b942-a4d58b8f1e2d.db"
  }
```

## Migration の実行

ここまでの対応を実行後に`Add-Migration`および`Update-Database`コマンドを実行してマイグレーションの適用を行うと SQLite をアプリケーションから使用することができます。

## おわりに

EFCore でのプロパイダー変更の方法についてまとめました。

個人開発をしていくなかで自分のように Azure SQL Database を利用している方だとプロパイダー変更をしたくなるようなケースは多いと思います。そういった方の助けになれればうれしいです。

## 参考

https://learn.microsoft.com/ja-jp/ef/core/managing-schemas/migrations/providers?tabs=vs

https://learn.microsoft.com/ja-jp/ef/core/managing-schemas/migrations/managing?tabs=vs#resetting-all-migrations