[EntityFrameworkCore]CodeFirstでテーブルに複合主キーを付ける


# 概要
EntityFrameworkCore下でCodeFirstを使ってテーブルに複合主キーを設定する方法がEntityFramework6下での作法から変わったようなので(今更ですが)正しいやり方を調査しました。

# 環境
- Microsoft.EntityFrameworkCore.Design(2.0.0)
- Microsoft.NETCore.Platforms(1.1.0)
- Visual Studio Community 2017 (15.3.3)


# 取り組んだこと

下記のようにEntityFramework6の頃の感覚でKeyとColumnのアノテーションで複合主キーの制約を付けたテーブルを書き、

``` C#:FooModel.cs(before)
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
public class FooModel
{
        [Key]
        [Column(Order = 1)]
        public int Hage { get; set; }
        [Key]
        [Column(Order = 2)]
        public int Foo { get; set; }
        public DateTime LastModified { get; set; }
}
```

DBContextにプロパティ追加してEntityFrameworkCoreを使ったプロジェクトでAdd-Migrationしたところ

``` sh:パッケージマネージャコンソール
PM> Add-Migration AddFooModel
System.InvalidOperationException: Entity type 'FooModel' has composite primary key defined with data annotations. To set composite primary key, use fluent API.
(中略)
Entity type 'FooModel' has composite primary key defined with data annotations. To set composite primary key, use fluent API.
```

「複合キーを設定する場合はfluentAPIを使ってください。」とのエラーメッセージが出ました。主キーが1つだけの場合はKeyによる指定もOKぽいですが、複合主キーを設定する場合には使えないようです。残念。

ということで今回使えないアノテーションをすべて外し、DBContext側にfluentAPIで複合主キーの制約を書きます。このとき、制約はDBContext.OnModelCreatingをオーバーライドして書き込みます。

``` C#:FooModel.cs(after)
using System;
public class FooModel
{
        public int Hage { get; set; }
        public int Foo { get; set; }
        public DateTime LastModified { get; set; }
}
```


```C#:SampleContext.cs
using Microsoft.EntityFrameworkCore;
public class SampleContext : DbContext
{
        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<FooModel>()
                .HasKey(c => new { c.Hage, c.Foo });
        }
}
```

これで再度Add-Migrationすると...

``` sh:パッケージマネージャコンソール
PM> Add-Migration AddFooModel
To undo this action, use Remove-Migration.
```

うまく行ったみたいですね！一応Migrationファイルも確認してみます。

``` C#:AddFooModel
    public partial class AddFooModel : Migration
    {
        protected override void Up(MigrationBuilder migrationBuilder)
        {
            migrationBuilder.CreateTable(
                name: "FooModel",
                columns: table => new
                {
                    Hage = table.Column<int>(type: "int", nullable: false),
                    Foo = table.Column<int>(type: "int", nullable: false),
                    LastModified = table.Column<DateTime>(type: "datetime2", nullable: false)
                },
                constraints: table =>
                {
                    table.PrimaryKey("PK_FooModel", x => new { x.Hage, x.Foo });
                });
        }
}
```

ちゃんと制約として複合主キーが設定されているようです。よしよし。


# まとめ
- EntityFramework6でも使っていた[Key][Column(Order=~)]のアノテーションで複合主キーをつけるやり方は終わったようです。
- EntityFrameworkCoreでテーブルの複合主キーを実現する場合は
DBContextのOnModelCreatingメソッドにてHasKeyメソッドで制約をつける。

# 参考URL
- https://docs.microsoft.com/en-us/ef/core/modeling/keys
    - 複合キーの使い方について
- https://msdn.microsoft.com/en-us/library/jj591617(v=vs.113).aspx
    - Fluent APIについての解説＆使用例
- https://stackoverflow.com/questions/40361034/entityframework-core-relation-to-composite-key
    - 今回はここ見て解決できました