EntityFrameworkのデータファーストでモデルクラスをINotifyPropertyChangedに対応させる

# EntityFrameworkサイコー

[EFのデータファースト](https://msdn.microsoft.com/en-us/library/jj206878(v=vs.113).aspx)が最高なので、`INotifyPropertyChanged`に対応したらもっとサイコーになるよね。
的な。

## INotifyPropertyChanged の実装超めんどい

- [INotifyPropertyChangedを実装する \- Qiita](https://qiita.com/Temarin/items/2d2a86d14f15ba078570)

なのでハイパー最高なNuGetのPropertyChanged.Fodyを使う。
[INotifyPropertyChangedを自動実装してくれるPropertyChanged\.fodyが超便利 \- Azureはじめました](http://10.hateblo.jp/entry/2015/10/28/105449)

上の記事は`PropertyChanged.Fody`のかなり古いバージョンなので今この通りに実装すると`そんな古い形式使ってんじゃねーよばーかばーか`的なエラーになるので注意。

## NotifyPropertyChanged.Fodyの実装方法

```csharp

public class HogeModel{
    public string Name{get;set;}
    public int AnyNumber{get;set;}
}
```

これを

```csharp
using System.ComponentModel;

public class HogeModel{
    public event PropertyChangedEventHandler PropertyChanged;

    public string Name{get;set;}
    public int AnyNumber{get;set;}
}
```
こうする。

後はプロジェクトに`FodyWeavers.xml`というファイルを追加して

```xml:FodyWeavers.xml
<?xml version="1.0" encoding="utf-8" ?>
<Weavers>
  <PropertyChanged/>
</Weavers>
```

こうするだけ。超便利。

## INotifyPr(略) をedmx で出力しているクラスにどう実装するか

edmxを構成するモデル出力用のT4テンプレートを直接編集すればOK

![スクリーンショット (80).png](https://qiita-image-store.s3.amazonaws.com/0/199750/46296bbb-fd44-249b-58ab-48637e6e9e21.png)

PropertyChanged.Fodyで追加する記述は

1. usingに`System.ComponentModel`を追加
2. class定義に`INotifyPropertyChanged`を追加
3. メンバに `PropertyChangedEventHandler`を追加

なのでそれぞれ追記する。

### 1. usingに`System.ComponentModel`を追加

usingを出力しているのは `codeStringGenerator.UsingDirectives()`なのでそこに追記

```csharp
public string UsingDirectives(bool inHeader, bool includeCollections = true)
{
    return inHeader == string.IsNullOrEmpty(_code.VsNamespaceSuggestion())
        ? string.Format(
            CultureInfo.InvariantCulture,
            "{0}using System;{1}" +
            "{2}",
            inHeader ? Environment.NewLine : "",
            (includeCollections ? (Environment.NewLine + "using System.Collections.Generic;") : "")
				+Environment.NewLine +"using System.ComponentModel;", //これ
            inHeader ? "" : Environment.NewLine)
        : "";
}

```

### 2. class定義に`INotifyPropertyChanged`を追加

class定義を出力してるのは`codeStringGenerator.EntityClassOpening()`

```csharp
public string EntityClassOpening(EntityType entity)
{
    return string.Format(
        CultureInfo.InvariantCulture,
        "{0} {1}partial class {2}{3}",
        Accessibility.ForType(entity),
        _code.SpaceAfter(_code.AbstractOption(entity)),
        _code.Escape(entity),
        ":INotifyPropertyChanged"); //これ
        //_code.StringBefore(" : ", _typeMapper.GetTypeName(entity.BaseType)));
}
```
(entity.BaseType使わないので横着した。使う場合は適宜修正を。)

### 3. メンバに `PropertyChangedEventHandler`を追加

テンプレートの先頭の方にある`EntityClassOpening(entity)`の後に直接記述

```csharp
<#=codeStringGenerator.UsingDirectives(inHeader: false)#>
<#=codeStringGenerator.EntityClassOpening(entity)#>
{
	#pragma warning disable 0067 
	public event PropertyChangedEventHandler PropertyChanged; //これ
	#pragma warning restore 0067 

```
ただ`PropertyChangedEventHandler`を追加しただけだと CS0067(未使用のメンバ)が表示されて大変鬱陶しいので`pragma warning disable - restore`を使って警告表示を抑制してみた。

[\[C\#\]コンパイル時の警告を抑制する \| anopara](https://anopara.net/2013/12/03/c%E3%82%B3%E3%83%B3%E3%83%91%E3%82%A4%E3%83%AB%E6%99%82%E3%81%AE%E8%AD%A6%E5%91%8A%E3%82%92%E6%8A%91%E5%88%B6%E3%81%99%E3%82%8B/)


あとはファイルを保存してコンパイルすればOK。
こんな感じに出力される。

```csharp
//------------------------------------------------------------------------------
// <auto-generated>
//     このコードはテンプレートから生成されました。
//
//     このファイルを手動で変更すると、アプリケーションで予期しない動作が発生する可能性があります。
//     このファイルに対する手動の変更は、コードが再生成されると上書きされます。
// </auto-generated>
//------------------------------------------------------------------------------

namespace models
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    
    public partial class 銀行マスタ:INotifyPropertyChanged
    {
    		public event PropertyChangedEventHandler PropertyChanged;
    		[Key]
    	    public string 銀行コード { get; set; }
    	    public string 銀行名 { get; set; }
    	    public string 銀行カナ { get; set; }
    }
}
```
いいね!

## 使いみちとか

`INotifyPropertyChanged`吐けばWinFormsのDataBindingとかWPFのBindingとかが勝手にリセットしてくれるので、ViewModel的に使ったりマジなんでもありでサイコー。