Help us understand the problem. What is going on with this article?

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

More than 3 years have passed since last update.

概要

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のアノテーションで複合主キーの制約を付けたテーブルを書き、

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したところ

パッケージマネージャコンソール
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をオーバーライドして書き込みます。

FooModel.cs(after)
using System;
public class FooModel
{
        public int Hage { get; set; }
        public int Foo { get; set; }
        public DateTime LastModified { get; set; }
}
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すると...

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

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

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

hahifu
C#メインのSEでした。最近はJS,pythonで遊ぶことが多いです。 ※ 記事の内容は僕の個人的な見解です。所属する/所属していた組織とは関係ありません。
https://github.com/hahifu
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away