リレーションシップの概要
このドキュメントでは、オブジェクト モデルとリレーショナル データベースの間で EF Core がどのようにマップされるかなど、これら 2 つの間のリレーションシップの表現の簡単な概要について説明します。
オブジェクト モデルのリレーションシップ
リレーションシップは、2 つのエンティティが互いを関連付ける方法を定義します。 たとえば、ブログの投稿をモデル化する場合、各投稿はそれが公開されているブログに関連し、ブログはそのブログに公開されているすべての投稿に関連します。
C# のようなオブジェクト指向言語では、ブログと投稿は通常、Blog
と Post
という 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; }
}
上記のクラスには、その Blog
と Post
が関連していることを示すものは何もありません。 これは、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; }
}
同様に、同じリレーションシップの反対方向は、それぞれの Blog
の Post
オブジェクトのコレクションとして表すことができます。
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.Posts
と Post.Blog
の各プロパティは "ナビゲーション" と呼ばれます。
リレーショナル データベースのリレーションシップ
リレーショナル データベースでは、リレーションシップは外部キーを使用して表わされます。 たとえば、SQL Server または Azure SQL を使用すると、次の表を使用して、Post
と Blog
クラスを表すことができます。
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]));
このリレーショナル モデルでは、Posts
と Blogs
の各テーブルに "主キー" 列が作成されます。 主キーの値により、各投稿またはブログが一意に識別されます。 さらに、Posts
テーブルには "外部キー" 列が作成されます。 Blogs
の主キー列 Id
は、Posts
テーブルの BlogId
外部キー列によって参照されます。 この列は "制約付き" です。つまり、Posts
の BlogId
列内のすべての値が、Blogs
の Id
列内の値と一致する必要があります。 この一致により、各投稿が関連するブログが決まります。 たとえば、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.Id
と Post
の外部キー プロパティ Post.BlogId
を、エンティティ型 (Blog.Posts
と Post.Blog
) 間の参照 ("ナビゲーション") に関連付けることができます。 これは、このような単純なリレーションシップを構築するときに EF によって自動的に行われますが、DbContext
の OnModelCreating
メソッドをオーバーライドするときに明示的に指定することもできます。 次に例を示します。
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);
}
これで、これらのプロパティはすべて、Blog
と Post
間の単一のリレーションシップの表現として共に一貫して動作します。
詳細情報
EF では、さまざまな種類のリレーションシップが多数サポートされており、これらのリレーションシップを表して構成する方法はさまざまです。 さまざまな種類のリレーションシップの例を参照するには、次を参照してください。
- 一対多リレーションシップ。これは、1 つのエンティティが任意の数の他のエンティティに関連付けられている場合です。
- 一対一リレーションシップ。これは、1 つのエンティティが別の 1 つのエンティティに関連付けられている場合です。
- 多対多リレーションシップ。これは、任意の数のエンティティが他の任意の数のエンティティに関連付けられている場合です。
EF を初めて使用する場合は、リレーションシップのしくみをつかむ方法として、上記の箇条書きでリンクされている例を試してみることをお勧めします。
リレーションシップ マッピングに関連するエンティティ型のプロパティを詳しく調べるには、次を参照してください。
- 「リレーションシップでの外部キーとプリンシパル キー」では、外部キーがデータベースにマップされる方法について説明します。
- 「リレーションシップのナビゲーション」では、リレーションシップのオブジェクト指向ビューを提供するために、ナビゲーションを外部キーに重ねて表示する方法について説明します。
EF モデルは、規則、マッピング属性、モデル ビルダー API の 3 つのメカニズムの組み合わせを使用して構築されます。 ほとんどの例は、モデル構築 API を示しています。 その他のオプションの詳細については、次を参照してください。
- リレーションシップ規則。これにより、エンティティ型、そのプロパティ、その型間のリレーションシップが検出されます。
- リレーションシップ マッピング属性。リレーションシップ構成の一部の側面で、モデル構築 API の代替として使用できます。
重要
モデル構築 API は、EF モデルの最後の信頼できるソースです。これは、規則によって検出された構成またはマッピング属性によって指定された構成よりも常に優先されます。 また、EF モデルのすべての側面を構成するための完全な忠実性を備えた唯一のメカニズムでもあります。
リレーションシップに関連するその他のトピックは次のとおりです。
- 連鎖削除では、
SaveChanges
またはSaveChangesAsync
を呼び出したときに関連エンティティを自動的に削除する方法をについて説明します。 - 所有エンティティ型では、特別な種類の "所有" リレーションシップが使用されます。これは、2 つの型間の接続が、ここで説明する "通常の" リレーションシップよりも強いことを意味します。 通常のリレーションシップに関してここで説明する概念の多くは、所有リレーションシップに引き継がれます。 ただし、所有リレーションシップには、独自の特殊な動作もあります。
ヒント
ドキュメントを読むときには必要に応じて「リレーションシップに関する用語の用語集」を参照し、使用される用語を理解するのに役立ててください。
リレーションシップの使用
モデルで定義されているリレーションシップは、さまざまな方法で使用できます。 次に例を示します。
- リレーションシップを使用すると、次の 3 つの方法のいずれかで関連データのクエリを実行できます。
- リレーションシップは、PK 値と FK 値の照合によるデータのシード処理で使用できます。
- リレーションシップを使用して、エンティティのグラフを追跡できます。 その後、リレーションシップは変更トラッカーによって次の用途に使用されます。
- リレーションシップの変更を検出して修正を実行する
SaveChanges
またはSaveChangesAsync
を使用して、外部キーの更新をデータベースに送信する
.NET