EntityFrameworkCore で SQLite3 を使ってみる（その１）

今さら感しかないですが、タイトル通り。 技術的には大体5年か10年くらい前の話題でしょうか...

その他には Code First を試してみるというのも目的にしています。

ソースコードは [GitHub](https://github.com/yumimatoba14/SQLiteTest) で公開しています。
git リポジトリ：https://github.com/yumimatoba14/SQLiteTest.git

# 背景

## 前提とする環境

* Visual Studio 2019
* .Net Framework 4.7.2
* EntityFrameworkCore 3.1.32
    * .Net Framework 4.7.2 (.NETStandard 2.0) をサポートする最後のバージョンが 3.1.32 のようだったので選択。
    * いつまでも EntityFramework ではあるまい、新しいものを使わねば、という意識もちょっとだけあったけど、結局ランタイムの制約により新しくならないというオチ。
* Code First を採用
    * Model First で EntityFramework を触ったことはあったけど、Code First を試してみようかなと。 検索して出てくる情報は Code First の方が多い印象ですが、はてさて。
* SQLite のバージョンにはこだわりなし。 EntityFrameworkCore.Sqlite に従う。

## なぜこの記事を作ったか

コーディング的な話はいくらでも情報は公開されているのですが、環境を作って使おうとするとどうなるのかという観点で落とし穴・障害物が多いと感じたことが理由です。自分のためにもメモが欲しいなあと。

# 1. 最低限の環境設定、Entity の追加

とりあえずコードとしては以下のあたりから。
> Revision: 90099b022c88c772018276a6adde60a64086271c
Message:
added minimum codes.


導入した nuget パッケージは以下。 いずれも 3.1.32
* Microsoft.EntityFrameworkCore.Sqlite
* Microsoft.EntityFrameworkCore.Tools

DbContext の派生クラス WfDbContext と Entity クラスとして Workflow クラスを足してあります。

次いでマイグレーション関係の操作（[参考][Ref1]）を行うためにパッケージマネージャーコンソールを起動します。
![スクリーンショット 2025-04-28 182612.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3124939/8aa73a3b-9283-42d1-abe4-e16630e7702c.png)

実体は PowerShell のようですね。

Enable-Migrations は現在は不要なようなので無視します。（実行すると「Enable-Migrations is obsolete. Use Add-Migration to start using Migrations.」と言われます。）
Add-Migration を実行します。
```
PM> Add-Migration InitialCreate
Build started...
Build succeeded.
System.TypeInitializationException: ...
```
Build succeeded というところまではよいのですが「System.Exception: Library e_sqlite3 not found」という例外が飛んでエラー終了します。 アセンブリの実行で用いられる e_sqlite3.dll が出力フォルダにコピーされておらず、モジュールをロードできていないのだと思われます。

以下のページによると、どうも nuget で取得したパッケージのバグであるっぽい。

https://github.com/ericsink/SQLitePCL.raw/issues/537

かつ開発者は直す気なさそう。（記事自体2023年と比較的最近。）回避策として packages.config を用いたパッケージ管理を PackageReference 方式に変えることを推奨しているっぽい。 （参考：[packages.config から PackageReference への移行 (Microsoft)][MoveToPackageRef]）
その他代案としてはビルドイベントで必要ファイルをコピーしても動きました。（runtimes/win-x86 とかのフォルダをコピーする。） 

今回は下記の通り 〇：× = 1：2 で(笑) packages.config の方式のままにしました。 今回はサンプルコードなんでどうでもよいのですが、いろんな部品の一部として使うときには致命的かなと。

* △ PackageReference の方が新しい方式っぽい。
* 〇 キャッシュをソリューションごとに作らなくてよい。
* ×× 全てのプロジェクトでサポートできているわけではなさそう。

DLL をコピーして Add-Migration を成功させる。 その後 Update-Database を実行することでデータベースの準備ができます。

## Add-Migration のもう一つのエラーの備忘録

もう一つ Add-Migration で生じたエラーについて。
PackageReferene 方式に置き換えて InitialCreate マイグレーションも作れてやれやれと思っていたら、以下のように急に Add-Migration できなくなって困った。

```
PM> Add-Migration Temp
Build started...
Build succeeded.
Add-Migration : null 値の式ではメソッドを呼び出せません。
発生場所 行:1 文字:1
+ Add-Migration Temp
+ ~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [Add-Migration]、RuntimeException
    + FullyQualifiedErrorId : InvokeMethodOnNull,Add-Migration
```
原因はパッケージマネージャコンソールの「既定のプロジェクト」の指定が別のプロジェクトに代わってしまっていたこと。 git で行きつ戻りつしているうちに変わってしまっていた様子。
今回共有したソリューションにはプロジェクトは一つしかないので発生しませんけどね。

## マイグレーション関係の操作に関するメモ

今回私が覚えたコマンドは以下の通りです。

* Add-Migration
    * DB を構築・更新するために必要な操作を抽出するためのコマンド。 引数で渡した InitialCreate はマイグレーションの名前と言ってよいと思う。 日付と時間(?)的な数字も付くので多分重複したり適当でもOK。
    * 作成されたファイルは Migrations フォルダに格納される。
    * ソリューションのスタートアッププロジェクトの選択なども動作に影響するっぽい。 ライブラリプロジェクトを作る構成を考える場合は多分[このページ][MultiProj]あたりを読むとよい。
* Update-Database
    * 今回で言えば SQLite のデータベースファイルを作成・テーブルのスキーマなどを登録してくれる。
    * データベースの中を見ると、マイグレーション履歴を記録したテーブルがあることが分かる。
* Remove-Migration
    * Add-Migration の逆操作で、最新のマイグレーションを削除します。 不要に作ったマイグレーションを削除し、一つにまとめるような時に使うと思います。

## まとめ、所感

思ったより長くなったのでここでいったん区切ります。（[その２](https://qiita.com/yumimatoba14/items/422b93ef9e7ab2b2658b)に続く。）
ここまでで SaveChanges() までできるようになりました。 コードのバージョンとしては以下のコミットに相当します。
> Revision: 9fef6e41323285376855bdcf241e72c3212de063
Message:
added InitialCreate migration.

* 開発中はしばしばデータを作るところからやり直したくなるため、スキーマのみ登録した空のファイルを git に登録しています。 空のデータベースに戻せる状態をすぐに作れるのは楽でよいですね。 開発中は重宝しそう。
* SQLite を使用していますが、コード上で SQLite であることを意識するのは ConnectionString を作るところだけのような気が。
    * EntityFramework の SQLite サポート状況がよいということかもしれません。 または Code First だからでしょうか。 いずれにしても DB 毎のコードの分離が少ないのは大変ありがたい。

## 参考ページ

以下のページを参考にさせていただきました。

https://qiita.com/massu/items/b2546a0d876e207de882

https://hirahira.blog/efcore-sqlite/

https://qiita.com/SugiuraF/items/111d433b8eb725de5ac4

https://increment-i.hateblo.jp/entry/entityframework/multiprojects

* [packages.config から PackageReference への移行 (Microsoft)][MoveToPackageRef]

https://qiita.com/namoshika/items/7d1bf911bc03ed03e17d

（qiitの関連ページとして挙がってきたページで、よくまとまっていたのでメモ。）

[Ref1]: https://qiita.com/massu/items/b2546a0d876e207de882
[MoveToPackageRef]: https://learn.microsoft.com/ja-jp/nuget/consume-packages/migrate-packages-config-to-package-reference
[MultiProj]: https://increment-i.hateblo.jp/entry/entityframework/multiprojects

# おまけ

## どのタグを使おうか
qiita に記事を上げる際のタグをどうしようと思ったので記事数を調べてみた。 (2025/4/29 現在)
| タグ名 | 検索された記事数 |
|:-:|:-:|
|EntityFramework|213|
|EntityFramework_Core|132|
|EFCore|12|
|EntityFrameworkCore|11|

最初 EntityFrameworkCore にしようと思っていたのですが、一番少なかった...

## シリーズ一覧

当初の想定よりこのシリーズのページが増えたので一覧を作成しました。 (2025/5/18 更新)

* その１（このページ）
    * 1\. 最低限の環境設定、Entity の追加
* [その２](https://qiita.com/yumimatoba14/items/422b93ef9e7ab2b2658b)
    * 2\. エンティティ間のリレーションを設定する
* [その３](https://qiita.com/yumimatoba14/items/87aa86ce1d909cce0ce0)
    * 3\. 削除時の Cascade 動作について
    * 4\. コードからのMigrationの実行
    * 5\. マイグレーションのリバート
    * 6\. マイグレーション用の DDL の書き出し
* [その４](https://qiita.com/yumimatoba14/items/020d255ca862ad299915)
    * 7\. e_sqlite3.dll が見つからない問題
    * 8\. そして e_sqlite3.dll を使わない方法へ