EF CoreでクラスライブラリのEntityに対してCode First Migrationを行う

# はじめに
ASP.NET Core でMVCのアプリを作ろうとした際、複数のプロジェクトで利用することを想定し、
Entity + DbContextを別プロジェクト（クラスライブラリ）としました。

しかしよく考えたら `StartUp.cs` も `appsetting.json` も無いのにどうやってマイグレーションをすればいいんだ？と思い調査したところ、自分の環境でうまくいく方法があったので、紹介します。

# 筆者の環境
* OS: macOS Mojave 10.14.5
* ASP.NET Coreのバージョン: 2.2

# やり方（抜粋）

1. クラスライブラリ側にnugetのEF Core関連パッケージを追加します
    * `Microsoft.EntityFrameworkCore`
    * `Microsoft.EntityFrameworkCore.Relational`
    * `Microsoft.EntityFrameworkCore.SqlServer`
2. DbContextをクラスライブラリ側に追加します
3. MVC側 `appsetting.json` に接続文字列を追加して、 `StartUp.cs` のDbContextのDI部分を以下のようにします

    ```Startup.cs
    services.AddDbContext<MyProjectEntitiesDbContext>(options =>
    {
    options.UseSqlSer:ve::r(Configuration.GetConnectionString("DefaultConnection"),
        assembly => assembly.MigrationsAssembly(typeof(MyProjectEntitiesDbContext).Assembly.FullName));
    });
    ```

4. MVC側プロジェクトディレクトリ内でコマンドを叩きます

    ```bash
    # --project: クラスライブラリの .csproject パス
    # --startup-project: MVC（クラスライブラリを利用する側）の .csproject パス
    dotnet ef migrations add InitialMigrations --project ../MyProjectEntities/MyProjectEntities.csproj --startup-project ./MyProjectMVC.csproj

    dotnet ef database update
    ```

# やり方（ソリューション作成からの一連の流れ）

### 1. ソリューション & 各プロジェクト作成

* MVC: `MyProjectMVC`
* クラスライブラリ: `MyProjectEntities`

<img width="427" alt="スクリーンショット 2019-07-10 22.11.28.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120023/9e54598f-151f-c5cd-58ff-3d7c0294c1e2.png">


### 2. クラスライブラリ側

#### 2-1. Personクラスを作成

`Entities` ディレクトリ下に普通に作ります

```Entities/Person.cs

namespace MyProjectEntities.Entities
{
    public class Person
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string Surname { get; set; }
    }
}

```

#### 2-2. EF Core関連のnuget パッケージインストール
以下の3つのパッケージをインストールします

* `Microsoft.EntityFrameworkCore`
* `Microsoft.EntityFrameworkCore.Relational`
* `Microsoft.EntityFrameworkCore.SqlServer`

#### 2-3. DbContextを作成する

今回は`Data` ディレクトリ下に作成しました（場所はどこでも良いはず）

```Data/MyProjectEntitiesDbContext.cs
using System.Linq;
using MyProjectEntities.Entities;
using Microsoft.EntityFrameworkCore;

namespace MyProjectEntities.Data
{
    namespace MyProjectEntities.Data
    {
        public class MyProjectEntitiesDbContext : DbContext
        {
            public MyProjectEntitiesDbContext(DbContextOptions<MyProjectEntitiesDbContext> options)
                : base(options)
            {
            }

            public DbSet<Person> Persons { get; set; }
        }
    }

}

```

これでクラスライブラリ側の作業は終わりです。

---

### 3. MVC側

#### 3-1. `appsetting.json` への接続文字列追加

普通に追加します

```appsetting.json
{
    "Logging": {
        "LogLevel": {
            "Default": "Warning"
        }
    },
    "AllowedHosts": "*",
    "ConnectionStrings": {
        "DefaultConnection": "hogehogefugafuga"
    }
}

```

#### 3-2. `StartUp.cs` で DbContextをDI


`assembly => assembly.MigrationsAssembly(typeof(クラスライブラリDbコンテキスト名).Assembly.FullName));` が通常と異なる部分です。

```StartUp.cs
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
    services.Configure<CookiePolicyOptions>(options =>
    {
        // This lambda determines whether user consent for non-essential cookies is needed for a given request.
        options.CheckConsentNeeded = context => true;
        options.MinimumSameSitePolicy = SameSiteMode.None;
    });
        
    services.AddDbContext<MyProjectEntitiesDbContext>(options =>
    {
        options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"),
            assembly => assembly.MigrationsAssembly(typeof(MyProjectEntitiesDbContext).Assembly.FullName));
    });


    services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
}
```

これでMVC側の作業は終わりです。

---

### 4. マイグレーション実施

#### 4-1. MVCプロジェクトのディレクトリに移動

コンソールで `ソリューションのディレクトリ` > `MVCプロジェクトのディレクトリ` に移動します。


```zsh
~/P/MyProject ❯❯❯ ls
MyProject.sln     MyProjectEntities MyProjectMVC
~/P/MyProject ❯❯❯ cd MyProjectMVC
```

#### 4-2. マイグレーションのコマンドを叩く
通常は`dotnet ef migrations add ${マイグレーションファイル名}` でよいのですが、
今回は以下のようにします
`dotnet ef migrations add ${マイグレーションファイル名} --project ${クラスライブラリの.csprojパス} --startup-project ${MVCプロジェクトの.csprojパス}`

```zsh
~/P/M/MyProjectMVC ❯❯❯ dotnet ef migrations add InitialMigrations --project ../MyProjectEntities/MyProjectEntities.csproj --startup-project ./MyProjectMVC.csproj
info: Microsoft.EntityFrameworkCore.Infrastructure[10403]
      Entity Framework Core 2.2.6-servicing-10079 initialized 'MyProjectEntitiesDbContext' using provider 'Microsoft.EntityFrameworkCore.SqlServer' with options: MigrationsAssembly=MyProjectEntities, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
Done. To undo this action, use 'ef migrations remove'
```

#### 4-3. DB反映

こちらは特に引数などは必要なく、普通に叩きます

```zsh
~/P/M/MyProjectMVC ❯❯❯ dotnet ef update
```