リレーションシップの概要

このドキュメントでは、オブジェクト モデルとリレーショナル データベースの間で EF Core がどのようにマップされるかなど、これら 2 つの間のリレーションシップの表現の簡単な概要について説明します。

オブジェクト モデルのリレーションシップ

リレーションシップは、2 つのエンティティが互いを関連付ける方法を定義します。 たとえば、ブログの投稿をモデル化する場合、各投稿はそれが公開されているブログに関連し、ブログはそのブログに公開されているすべての投稿に関連します。

C# のようなオブジェクト指向言語では、ブログと投稿は通常、BlogPost という 2 つのクラスで表されます。 次に例を示します。

public class Blog
{
    public string Name { get; set; }
    public virtual Uri SiteUri { get; set; }
}
public class Post
{
    public string Title { get; set; }
    public string Content { get; set; }
    public DateTime PublishedOn { get; set; }
    public bool Archived { get; set; }
}

上記のクラスには、その BlogPost が関連していることを示すものは何もありません。 これは、Post から、公開先である Blog への参照を追加することで、オブジェクト モデルに追加できます。

public class Post
{
    public string Title { get; set; }
    public string Content { get; set; }
    public DateOnly PublishedOn { get; set; }
    public bool Archived { get; set; }

    public Blog Blog { get; set; }
}

同様に、同じリレーションシップの反対方向は、それぞれの BlogPost オブジェクトのコレクションとして表すことができます。

public class Blog
{
    public string Name { get; set; }
    public virtual Uri SiteUri { get; set; }

    public ICollection<Post> Posts { get; }
}

Blog から Post へ、また、逆に Post から Blog へと戻るこのつながりは、EF Core では "リレーションシップ" と呼ばれます。

重要

通常、単一のリレーションシップは、どちらの方向でも走査できます。 この例では、これは Blog.Posts プロパティを使用する Blog から Post への場合と、Post.Blog プロパティを使用して Post から Blog へ戻る場合です。 これは 2 つではなく 1 つのリレーションシップです。

ヒント

EF Core では、Blog.PostsPost.Blog の各プロパティは "ナビゲーション" と呼ばれます。

リレーショナル データベースのリレーションシップ

リレーショナル データベースでは、リレーションシップは外部キーを使用して表わされます。 たとえば、SQL Server または Azure SQL を使用すると、次の表を使用して、PostBlog クラスを表すことができます。

CREATE TABLE [Posts] (
    [Id] int NOT NULL IDENTITY,
    [Title] nvarchar(max) NULL,
    [Content] nvarchar(max) NULL,
    [PublishedOn] datetime2 NOT NULL,
    [Archived] bit NOT NULL,
    [BlogId] int NOT NULL,
    CONSTRAINT [PK_Posts] PRIMARY KEY ([Id]),
    CONSTRAINT [FK_Posts_Blogs_BlogId] FOREIGN KEY ([BlogId]) REFERENCES [Blogs] ([Id]) ON DELETE CASCADE);

CREATE TABLE [Blogs] (
    [Id] int NOT NULL IDENTITY,
    [Name] nvarchar(max) NULL,
    [SiteUri] nvarchar(max) NULL,
    CONSTRAINT [PK_Blogs] PRIMARY KEY ([Id]));

このリレーショナル モデルでは、PostsBlogs の各テーブルに "主キー" 列が作成されます。 主キーの値により、各投稿またはブログが一意に識別されます。 さらに、Posts テーブルには "外部キー" 列が作成されます。 Blogs の主キー列 Id は、Posts テーブルの BlogId 外部キー列によって参照されます。 この列は "制約付き" です。つまり、PostsBlogId 列内のすべての値が、BlogsId 列内の値と一致する必要があります。 この一致により、各投稿が関連するブログが決まります。 たとえば、Posts テーブルのある行の BlogId の値が 7 の場合、その行によって表される投稿は、主キー 7 を使用してブログに公開されます。

EF Core でのリレーションシップのマッピング

EF Core のリレーションシップ マッピングとは、リレーショナル データベースで使用される主キー/外部キー表現を、オブジェクト モデルで使用されるオブジェクト間の参照にマッピングすることです。

最も基本的な意味では、これには次のことが含まれます。

  • 各エンティティ型に主キー プロパティを追加する。
  • 1 つのエンティティ型に外部キー プロパティを追加する。
  • エンティティ型間の参照を主キーと外部キーに関連付けて、単一のリレーションシップ構成を形成する。

このマッピングが行われると、EF により、オブジェクト間の参照が変更されたときに必要に応じて外部キーの値が変更され、外部キーの値が変更されたときに必要に応じてオブジェクト間の参照が変更されます。

Note

主キーは、リレーションシップのマッピング以外にも使用されます。 詳細については、「キー」を参照してください。

たとえば、上記のエンティティ型は、主キーと外部キーのプロパティを使用して更新できます。

public class Blog
{
    public int Id { get; set; }
    public string Name { get; set; }
    public virtual Uri SiteUri { get; set; }

    public ICollection<Post> Posts { get; }
}
public class Post
{
    public int Id { get; set; }
    public string Title { get; set; }
    public string Content { get; set; }
    public DateTime PublishedOn { get; set; }
    public bool Archived { get; set; }

    public int BlogId { get; set; }
    public Blog Blog { get; set; }
}

ヒント

主キーと外部キーのプロパティは、エンティティ型のパブリックに表示されるプロパティである必要はありません。 ただし、プロパティが非表示の場合でも、EF モデルにまだ存在していることを認識することが重要です。

Blog の主キー プロパティ Blog.IdPost の外部キー プロパティ Post.BlogId を、エンティティ型 (Blog.PostsPost.Blog) 間の参照 ("ナビゲーション") に関連付けることができます。 これは、このような単純なリレーションシップを構築するときに EF によって自動的に行われますが、DbContextOnModelCreating メソッドをオーバーライドするときに明示的に指定することもできます。 次に例を示します。

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Blog>()
        .HasMany(e => e.Posts)
        .WithOne(e => e.Blog)
        .HasForeignKey(e => e.BlogId)
        .HasPrincipalKey(e => e.Id);
}

これで、これらのプロパティはすべて、BlogPost 間の単一のリレーションシップの表現として共に一貫して動作します。

詳細情報

EF では、さまざまな種類のリレーションシップが多数サポートされており、これらのリレーションシップを表して構成する方法はさまざまです。 さまざまな種類のリレーションシップの例を参照するには、次を参照してください。

EF を初めて使用する場合は、リレーションシップのしくみをつかむ方法として、上記の箇条書きでリンクされている例を試してみることをお勧めします。

リレーションシップ マッピングに関連するエンティティ型のプロパティを詳しく調べるには、次を参照してください。

EF モデルは、規則、マッピング属性、モデル ビルダー API の 3 つのメカニズムの組み合わせを使用して構築されます。 ほとんどの例は、モデル構築 API を示しています。 その他のオプションの詳細については、次を参照してください。

重要

モデル構築 API は、EF モデルの最後の信頼できるソースです。これは、規則によって検出された構成またはマッピング属性によって指定された構成よりも常に優先されます。 また、EF モデルのすべての側面を構成するための完全な忠実性を備えた唯一のメカニズムでもあります。

リレーションシップに関連するその他のトピックは次のとおりです。

  • 連鎖削除では、SaveChanges または SaveChangesAsync を呼び出したときに関連エンティティを自動的に削除する方法をについて説明します。
  • 所有エンティティ型では、特別な種類の "所有" リレーションシップが使用されます。これは、2 つの型間の接続が、ここで説明する "通常の" リレーションシップよりも強いことを意味します。 通常のリレーションシップに関してここで説明する概念の多くは、所有リレーションシップに引き継がれます。 ただし、所有リレーションシップには、独自の特殊な動作もあります。

ヒント

ドキュメントを読むときには必要に応じて「リレーションシップに関する用語の用語集」を参照し、使用される用語を理解するのに役立ててください。

リレーションシップの使用

モデルで定義されているリレーションシップは、さまざまな方法で使用できます。 次に例を示します。