EntityFrameworkを使ってみた。

## 注意
今回の記事ではMigrationファイルを作成し反映する作業が多々あります。

説明は一度はしますが、反映に関するコマンドは~~面倒なので~~省略されることがあります。

そのため、まずは **次項にて** 頻出コマンドを記載しておきます。

また、こういったしっかりした記事は初めて書きますので、何卒ご容赦いただければと思います。

## 頻出コマンド(PackageManagerConsole)

```ツール(T)``` -> ```Nugetパッケージマネージャ(N)``` -> ```パッケージマネージャコンソール(O)```

で入力するコマンドです。

### Migration機能の有効化

プロジェクトにてMigrationの有効化を行うコマンドです。
一度有効化すれば問題ありません。

```powershell:PackageManagerConsole
Enable-Migrations
```

なお、接続先変更等行った場合は再度このコマンドを叩く必要がありそうです。私の場合、有効化したあとに接続先を変更してMigrateしても変更前の接続先に反映されてしまいました。

再度有効化(厳密には再設定?)を行うには ``` -Force``` オプションをつければOKです。
```powershell:PackageManagerConsole
Enable-Migrations -Force
```

### Migrateファイルの作成

gitで ``` commit -m "コメント" ``` のあとに ```push ```を行うのと同様、

Migrateファイルに一度名前をつけて、その後反映させる必要があります。

```powershell:PackageManagerConsole
Add-Migration MigrationName
```

### データベースへの反映

そのままなので補足はありません。

```powershell:PackageManagerConsole
Update-Database
```

## 参考サイト

### EntityFrameworkについて
[インクリメンタルなはいかつにっき](http://increment-i.hateblo.jp/archive/category/Entity%20Framework) 様

上記リンクはEntityFrameworkのタグです。
なお、本記事は上記リンクを知識定着のために書き直したものです。内容としては上記リンク先の内容と大差ありません。

### 列属性について
https://qiita.com/mrpero/items/607c31895d77815a77cb


## 開発環境

Visual Studio 2017 Community

## EntityFrameworkって？

ASP.netで使用できるDB関連のパッケージです。

LaravelやRoRでできる、**スキャフォールド(Scaffold)** や **マイグレーション(Migration)** ができます。

 **コードファースト(CodeFirst)** という考えのもと、モデルを先に作ってしまえば、それに基づいてテーブルを作ってくれます。

なお、**Seeder**もあります。
魅力的。


## 参照設定

Nugetから以下のパッケージを落としておきましょう。

1.  EntityFramework
1.  EntityFramework.ja

後者はお好みですが、メッセージが日本語になるので。


```ツール(T)``` -> ```Nugetパッケージマネージャ(N)``` -> ```ソリューションのNugetパッケージの管理```

で上記パッケージを検索してインストールするもよし、

```ツール(T)``` -> ```Nugetパッケージマネージャ(N)``` -> ```パッケージマネージャコンソール(O)```

で以下コマンドを叩いても可。

```powershell:PackageManagerConsole
Install-Package EntityFramework
Install-Package EntityFramework.ja
```

## プロジェクトの作成
今回はC#で作ってみました。WebAPIは対応せず以下の通り設定してます。

ソリューション名は **EntityFrameworkTest** ということで略して **EFTest** としてます。

特に設定もないのでそのまま作成しましょう。

- 新規プロジェクトの作成

```Ctrl + Shift + N``` で「新しいプロジェクト」画面を開きます。

※ もちろん ```ファイル(F)``` -> ```新規作成(N)``` -> ```プロジェクト(P) ``` でも可能

続いて、表示された画面の左のツリーから
 
 ```Visual C#``` -> ```Web``` 
 
 中央のリストから
 
  ```ASP.NET Webアプリケーション(.NET Framework)``` 

を選択してソリューションを作成。
次の「 新しいASP. NET Webアプリケーション 」画面では
**MVC** を選択。画面下部のチェックボックスはMVCだけでよいかと。

作成完了したら、ソリューションエクスプローラーにつらつらとファイル群。

## 接続設定
参考にさせていただいたサイト様では中盤に設定の記載がありますが、地味につまづきポイントなのではじめに記載します。

なお、次に紹介する接続文字列の設定をしないと、デフォルトの長ったらしい名前でDBが作られてしまうのでご注意。

```xml:Web.config
<?xml version="1.0" encoding="utf-8"?>
<configuration>  
  <!-- 中略 -->
  <!-- ↓を追加 -->
  <connectionStrings>
    <add name="EFTestDbContext" connectionString="Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=EFTestDB" providerName="System.Data.SqlClient"/>
  </connectionStrings>
</configuration>
```

```connectionStrings``` 要素が接続情報を管理しています。

今回重要視するのは
**connectionString** 属性。この値内にある **Initial Catalog** で設定している「EFTestDB」がDBの名前です。



## クラスについて
### DbContextクラス
こちらは、簡単に言うとModelとDBとの間を仲介するクラスです。CRUD処理時はこのクラスを介します。

このクラスはEntityFrameworkに用意されており、実装していきます。

```C#:Models/EFTestDbContext.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace EFTest.Models
{
	public class EFTestDbContext : System.Data.Entity.DbContext
	{
	}
}
```

このクラスの中身はModelと合わせて追加してくので、慌てない。



## Migratio設定

続いてはMigrationの有効化が必要なんですね。プロジェクト単位で必要なようです。有効化はパッケージマネージャーで以下。

```powershell:PackageManagerConsole
Enable-Migrations
```

少し待つと「完了しました」のメッセージ。

※このときのメッセージで、「コンテキストが既存のデータベースを対象にしているかをチェックしています」とあるので、DbContextクラスを作る前にやったらだめなのかな…？試してないです。


さて、完了後、設定ファイルが追加されるのがわかると思います。

**Migrations/Configration.cs** ができてます。私はこれだけでテンションが上ってました。今後、Migrate毎に Migrationsフォルダにファイルが追加されていくので乞うご期待。

```C#:Migrations/Configration.cs
namespace EFTest.Migrations
{
    using System;
    using System.Data.Entity;
    using System.Data.Entity.Migrations;
    using System.Linq;

    internal sealed class Configuration : DbMigrationsConfiguration<EFTest.Models.EFTestDbContext>
    {
        public Configuration()
        {
            AutomaticMigrationsEnabled = false;
        }

        protected override void Seed(EFTest.Models.EFTestDbContext context)
        {
            //  This method will be called after migrating to the latest version.

            //  You can use the DbSet<T>.AddOrUpdate() helper extension method 
            //  to avoid creating duplicate seed data.
        }
    }
}

```

こちらがその設定ファイルです。 ```protected override void Seed``` の文字があります。そうです、 **Seeder** でございます。

使うときに改めて。とりあえずこれにて設定は完了。

## Migrate
第一回Migrateをしてみようと思います。
そのためには、モデルを作らないとですね。
では参考サイトに倣って都道府県テーブルを作りましょう。

| Code | Name | Kana      |
|:-----|:-----|:----------|
| 01   |北海道 |ホッカイドウ|
| 02   |青森県 |アオモリケン|
| ...  | ...  | ...       |

こんなやつ。
クラス名(テーブル名)は **Prefectures** としましょう。で、必要なフィールドをプロパティとして宣言。ここでValidationの条件等も設定できますが割愛。


```C#:Models/Prefecture.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace EFTest.Models
{
	public class Prefecture
	{
		public int Id { get; set; }

		public string Code { get; set; }

		public string Name { get; set; }

		public string Kana { get; set; }
	}
}

```

IDは設定しておかないと、怒られますので追加します。ちなみに、デフォルトだとIDって名前じゃないと主キーとして認識されないようです。「この名前の列がいい！！」って言う人用に、設定もできますので後述。

続いて、DbContextも修正します。
モデルを追加したらそのDbSetも設定して上げる必要があるんですね。

```C#:Models/EFTestDbContext.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Data.Entity;

namespace EFTest.Models
{
	public class EFTestDbContext : DbContext
	{
		public DbSet<Prefecture> Prefecture { get; set; }
	}
}

```

laravelなどを使ったことがある方は何となく分かるかもしれませんが、Migrateには名前を設定して上げる必要があります。

DbSetまで書けたら、PackageManagerConsoleで次のコマンドを叩いてMigrationに名称をつけてあげる必要があります。

```powershell:PackageManagerConsole
Add-Migration CreatePrefecture
```

問題なければ、そのまま完了。
黄色い背景文字で注意書きもありますので見ておいてくださいまし。

完了すると MigrationディレクトリにMigrationファイルが作成されています。

```C#:Migrations/201902020130551_CreatePrefecture.cs
namespace EFTest.Migrations
{
    using System;
    using System.Data.Entity.Migrations;
    
    public partial class CreatePrefecture : DbMigration
    {
        public override void Up()
        {
            CreateTable(
                "dbo.Prefectures",
                c => new
                    {
                        Id = c.Int(nullable: false, identity: true),
                        Code = c.String(),
                        Name = c.String(),
                        Kana = c.String(),
                    })
                .PrimaryKey(t => t.Id);
            
        }
        
        public override void Down()
        {
            DropTable("dbo.Prefectures");
        }
    }
}

```

Migration経験者だと **タイムスタンプ + Migration名称** のファイル名に馴染みがあるかもしれませんね。

## Update Database

Migrationファイルを作成しただけではDBに反映はされないので、PackageManagerConsoleで次のコマンドでを叩く必要があります。

```powershell:PackageManagerConsole
Update-Database
```

これで、 ``` web.config ``` に記載した名称のDB及び、Migrationファイル通りのテーブルが作られます。

## (こらむ) Migrationのロールバック

Migrationがあるのであれば、間違えたときのロールバックもあるはず。あってほしいですよね。

無論あります。

まず、Migrationの状況を確認しましょう。

**Migrations** ディレクトリの中にあるファイルでもMigrationの状況はわかりますが、

```powershell:PackageManagerConsole
Get-Migrations
```

でも確認できます。

今回は一つしか作っていないので戻すも何もありませんが、戻すMigrationを決めたら以下コマンドで戻します。今回は例としてInitialというバージョンに戻すことを想定します。

```powershell:PackageManagerConsole
Update-Database -TargetMigration Initial
```

以上、Migrationの反映方法から戻し方、DBの設定方法などでした。






## 列属性、テーブル属性の変更について

続いては、プラスαの情報として属性についてお伝えします。
アノテーションを用いることで、例えば型や長さ、NotNullなどが設定できます

### 属性(Table)

まずはテーブルの属性変更。テーブルの属性って言っても主に変えることがありそうなのはテーブル名ですよね。

```C#:Models/Prefecture.cs
using System.ComponentModel.DataAnnotations.Schema;

namespace EFTest.Models
{
	[Table("Hoge", Schema = "fuga")]
	public class Prefecture
	{
		public int Id { get; set; }

		public string Code { get; set; }

		public string Name { get; set; }

		public string Kana { get; set; }
	}
}
```

こうすることで、テーブル名は ```dbo.Prefectures``` から  ```fuga.Hoge``` となります。

なお、Schemaは指定しない場合は変更ありません。

### 属性(Column)

https://qiita.com/mrpero/items/607c31895d77815a77cb#displayname

今回はこちらをご参照ください。

また折を見て私もまとめます。


## 1 : N, N : 1, N : N

Entity Frameworkでは(でも?)ありがちな多対多は実装できます。

例として下図のようなものを実装します。
(若干列の位置が違いますごめんなさい)

![uml.PNG](https://qiita-image-store.s3.amazonaws.com/0/46074/e8c07eb7-0ab7-7fa0-2d61-58b1882b1c90.png)


モデルの実装及びControllerでの呼び出し方法については下記Githubにて公開しますのでご参照ください。
[Github EntityFrameworkSample](https://github.com/cresta522/EntityFrameworkSample)


## 最後に

Qiitaにてしっかり書くのは初めてなので皆さんが毎回どれだけ大変な思いをされているか思い知りました。。

今後は、もっと視点を広く持ってわかりやすい共有記事や備忘録を書きますのでよろしくお願いいたします。