EF Core のマイグレーションがすごい便利だった

Windows アプリの DB 周りを調べていて、EF Core のマイグレーションがかなり便利だなと思ったので、構築手順とマイグレーション方法について記載します。

# EF Core とは

公式サイトより引用です。

> Entity Framework Core は、.NET 用の最新のオブジェクト データベース マッパーです。 LINQ クエリ、変更の追跡、更新、スキーマの移行がサポートされています。 EF Core は、SQL Database (オンプレミスと Azure)、SQLite、MySQL、PostgreSQL、Azure Cosmos DB などの多くのデータベースに対応しています。

# 環境

- Visual Studio 2019
- .NET Core 3.0
- EF Core 3.1.7
- SQLite

# 手順

## 1. WPF アプリのプロジェクトを新規作成し、以下の NuGet パッケージをインストールする

```
Install-Package Microsoft.EntityFrameworkCore.Sqlite
Install-Package Microsoft.EntityFrameworkCore.Proxies
Install-Package Microsoft.EntityFrameworkCore.Tools
```

- Microsoft.EntityFrameworkCore.SQLite（SQLite 本体）
- Microsoft.EntityFrameworkCore.Proxies（データの遅延読み込みサポート用）
- Microsoft.EntityFrameworkCore.Tools（マイグレーション用）

## 2. EF Core のチュートリアルに記載のソース（C#、XAML）を一通り書き切る（ビルドはまだしない）

私が使ったのは EF Core のチュートリアルです。
[WPF の使用を開始する - EF Core | Microsoft Docs](https://docs.microsoft.com/ja-jp/ef/core/get-started/wpf)

以下にサンプルコードもあるので、手書きせずともそちらを使っても大丈夫です。
[GetStartedWPF](https://github.com/dotnet/EntityFramework.Docs/tree/master/samples/core/WPF/GetStartedWPF)

ただし、まだビルドはしないように気をつけてください。
理由は後ほど説明します。

## 3. `MainWindow.xaml.cs`の`Window_Loaded`を以下の通り書き換える

```cs:MainWindow.xaml.cs
private void Window_Loaded(object sender, RoutedEventArgs e)
{
    // DBのマイグレーション
    _context.Database.Migrate();

    // load the entities into EF Core
    _context.Categories.Load();

    // bind to the source
    categoryViewSource.Source =
        _context.Categories.Local.ToObservableCollection();
}
```

具体的には、`_context.Database.EnsureCreated();`と書かれていたところを、`_context.Database.Migrate();`に書き換えます。
書き換える理由としては以下の通りです（公式ドキュメント引用）

> データベースが既に存在する場合、EnsureCreated() によってデータベースのスキーマとシードデータが更新されないことに注意してください。 リレーショナルデータベースの場合、移行を使用する予定がある場合は EnsureCreated() を呼び出さないでください。

ビルドをしないでください、と言ったのもこのためです。
もしビルドをしてしまった場合は、生成された`products.db`を削除してください。

## 4. パッケージマネージャーコンソールで以下のコマンドを実行し、Migrations フォルダおよびその配下に C#ファイルがいくつか自動生成されることを確認する

```
Add-Migration InitialCreate
Update-Database
```

## 5. ビルド&アプリを実行する

`products.db`が生成されるはずです。

# マイグレーションのやり方

個人的に便利だと思ったのがこのマイグレーションです。
本来ならクエリ文を手書きして適用する形でいろいろめんどくさいのですが、EF Core ではクエリ文を手書きせずとも簡単なコマンドで簡単に実現できます。

## 1. `Product.cs`に適当なカラムを追加するなどする

例えば`Product.cs`を以下のように書き換えてみます。

```cs:Product.cs
namespace GetStartedWPF
{
    public class Product
    {
        public int ProductId { get; set; }
        public string Name { get; set; }
        public int Price { get; set; } // 新しく追加したカラム
        public int CategoryId { get; set; }
        public virtual Category Category { get; set; }
    }
}
```

## 2. 以下のコマンドを実行し、Migrations フォルダの配下に C#ファイルが新たに自動生成されることを確認する

```
Add-Migration AddProductPrice
Update-Database
```

## 3. ビルド&アプリ実行

`products.db`を見ると、1 で変更した内容が反映されているはずです。

# UWP アプリで EF Core を使う際の注意

UWP アプリにて EF Core のマイグレーションをやるときは、`App.xaml.cs`でマイグレーションしないと動かないので注意です。
WPF アプリなどを Windows アプリケーション パッケージ プロジェクトでパッケージングする場合も同様です。

```cs:App.xaml.cs
public App()
{
    using (var dbContext = new ProductContext())
        dbContext.Database.Migrate();
}
```

# 参考 URL

- [WPF の使用を開始する - EF Core | Microsoft Docs](https://docs.microsoft.com/ja-jp/ef/core/get-started/wpf)
- [移行の概要 - EF Core | Microsoft Docs](https://docs.microsoft.com/ja-jp/ef/core/managing-schemas/migrations/?tabs=vs)
- [移行の適用-EF Core | Microsoft Docs](https://docs.microsoft.com/ja-jp/ef/core/managing-schemas/migrations/applying?tabs=vs)
- [データシード処理-EF Core | Microsoft Docs](https://docs.microsoft.com/ja-jp/ef/core/modeling/data-seeding)
- [UWP で Entity Framework Core を使いたい - みかづきメモ](https://mikazuki.hatenablog.jp/entry/2016/10/13/023412)