一対一のリレーションシップ
一対一リレーションシップは、あるエンティティが最大で 1 つの他のエンティティに関連付けられている場合に使われます。 たとえば、Blog
は 1 つの BlogHeader
を持ち、その BlogHeader
は 1 つの Blog
に属しています。
このドキュメントは、多くの例を中心に構成されています。 最初に一般的なケースの例をいくつか示し、そこで概念も紹介します。 後の例では、あまり一般的でない種類の構成について説明します。 ここでの適切なアプローチは、最初にいくつかの例と概念を理解してから、具体的なニーズに基づいて後の例に進むことです。 このアプローチに基づいて、単純な "必須" と "オプション" の一対一リレーションシップから始めます。
ヒント
以下のすべての例のコードは、OneToOne.cs にあります。
必須の一対一
// Principal (parent)
public class Blog
{
public int Id { get; set; }
public BlogHeader? Header { get; set; } // Reference navigation to dependent
}
// Dependent (child)
public class BlogHeader
{
public int Id { get; set; }
public int BlogId { get; set; } // Required foreign key property
public Blog Blog { get; set; } = null!; // Required reference navigation to principal
}
一対一リレーションシップは、次のもので構成されます。
- プリンシパル エンティティに対する 1 つ以上のプライマリ キーまたは代替キー プロパティ。 たとえば、
Blog.Id
のようにします。 - 依存エンティティに対する 1 つ以上の外部キー プロパティ。 たとえば、
BlogHeader.BlogId
のようにします。 - 必要に応じて、依存エンティティを参照するプリンシパル エンティティに対する参照ナビゲーション。 たとえば、
Blog.Header
のようにします。 - 必要に応じて、プリンシパル エンティティを参照する依存エンティティに対する参照ナビゲーション。 たとえば、
BlogHeader.Blog
となります。
ヒント
一対一リレーションシップのどちらをプリンシパルで、どちらが依存側かは、必ずしも明らかではありません。 いくつか考慮事項があります。
- 2 つの型のデータベース テーブルが既に存在する場合、外部キー列があるテーブルを依存型にマップする必要があります。
- ある型が、もう一方の型がないと論理的に存在できない場合、通常、その型は依存型です。 たとえば、存在しないブログのヘッダーを持つことは意味がないので、当然、
BlogHeader
は依存型です。 - 自然な親子リレーションシップがある場合、通常は子が依存型です。
したがって、この例のリレーションシップの場合は、次のようになります。
- 外部キー プロパティ
BlogHeader.BlogId
は null 許容ではありません。 これにより、すべての依存側 (BlogHeader
) は "何らかのプリンシパル (Blog
) に関連付けられている必要があり"、外部キー プロパティには何らかの値が設定されている必要があるため、リレーションシップは "必須" になります。 - 両方のエンティティには、リレーションシップの反対側にある関連エンティティを指すナビゲーションがあります。
注意
必須リレーションシップにより、すべての依存エンティティを何らかのプリンシパル エンティティに関連付ける必要があることが保証されます。 ただし、プリンシパル エンティティは依存エンティティなしで "常に" 存在できます。 つまり、必須リレーションシップは、依存エンティティが常に存在することを示すわけでは "ありません"。 プリンシパルが依存に確実に関連付けられるようにする方法は EF モデルにはなく、リレーショナル データベースにもそれを行う標準的な方法はありません。 これが必要な場合は、アプリケーション (ビジネス) ロジックで実装する必要があります。 詳細については、「必須のナビゲーション」を参照してください。
ヒント
2 つのナビゲーション (1 つは依存側からプリンシパル側、もう 1 つは逆のプリンシパル側から依存側) があるリレーションシップは、双方向リレーションシップと呼ばれます。
このリレーションシップは、規則によって検出されます。 つまり、
Blog
はリレーションシップのプリンシパル側として検出され、BlogHeader
は依存側として検出されます。BlogHeader.BlogId
は、プリンシパル側のBlog.Id
主キーを参照する依存側の外部キーとして検出されます。BlogHeader.BlogId
が null 許容ではないので、リレーションシップは必須として検出されます。Blog.BlogHeader
は、参照ナビゲーションとして検出されます。BlogHeader.Blog
は、参照ナビゲーションとして検出されます。
重要
C# の null 許容参照型を使う場合、外部キー プロパティが null 許容であれば、依存からプリンシパルへのナビゲーションは null 許容である必要があります。 外部キー プロパティが null 非許容の場合は、ナビゲーションは null 許容でも非許容でもかまいません。 この例の場合、BlogHeader.BlogId
は null 非許容であり、BlogHeader.Blog
も null 非許容です。 通常、EF は Blog
インスタンスを設定し、完全に読み込まれたリレーションシップではそれを null にできないため、= null!;
コンストラクトを使ってこれは意図的なものであると C# コンパイラに伝えます。 詳細については、「Null 許容参照型の使用」を参照してください。
リレーションシップのナビゲーション、外部キー、または必須とオプションの性質が規則によって検出されない場合は、これらの設定を明示的に構成できます。 次に例を示します。
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.HasOne(e => e.Header)
.WithOne(e => e.Blog)
.HasForeignKey<BlogHeader>(e => e.BlogId)
.IsRequired();
}
上の例では、リレーションシップの構成はプリンシパル エンティティ型 (Blog
) から始まります。 すべてのリレーションシップと同様に、そうではなく依存エンティティ型 (BlogHeader
) から始まる場合とまったく同じです。 次に例を示します。
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<BlogHeader>()
.HasOne(e => e.Blog)
.WithOne(e => e.Header)
.HasForeignKey<BlogHeader>(e => e.BlogId)
.IsRequired();
}
これらのオプションは、どちらかが他より優れているということはありません。両方ともまったく同じ構成になります。
ヒント
プリンシパル側から一度開始し、依存側からもう一度開始するというように、リレーションシップを 2 回構成する必要はありません。 また、リレーションシップのプリンシパル側と依存側を半分ずつ個別に構成しようとしても、通常はうまくいきません。 どちらか一方の側から各リレーションシップを構成することを選んだら、構成コードを 1 回だけ記述します。
オプションな一対一
// Principal (parent)
public class Blog
{
public int Id { get; set; }
public BlogHeader? Header { get; set; } // Reference navigation to dependent
}
// Dependent (child)
public class BlogHeader
{
public int Id { get; set; }
public int? BlogId { get; set; } // Optional foreign key property
public Blog? Blog { get; set; } // Optional reference navigation to principal
}
これは前の例と同じですが、外部キー プロパティとプリンシパルへのナビゲーションが null 許容である点が異なります。 これにより、リレーションシップは "オプション" になります。これは、外部キー プロパティとナビゲーションを null
に設定すると、依存側 (BlogHeader
) をその"どの" プリンシパル (Blog
) にも関連付けることが "できない" からです。
重要
C# の null 許容参照型を使う場合、外部キー プロパティが null 許容であれば、依存からプリンシパルへのナビゲーション プロパティは null 許容である必要があります。 この場合、BlogHeader.BlogId
は null 許容であるため、BlogHeader.Blog
も null 許容である必要があります。 詳細については、「Null 許容参照型の使用」を参照してください。
前と同じように、このリレーションシップは規則によって検出されます。 リレーションシップのナビゲーション、外部キー、または必須とオプションの性質が規則によって検出されない場合は、これらの設定を明示的に構成できます。 次に例を示します。
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.HasOne(e => e.Header)
.WithOne(e => e.Blog)
.HasForeignKey<BlogHeader>(e => e.BlogId)
.IsRequired(false);
}
主キーと主キーのリレーションシップがある必須の一対一
// Principal (parent)
public class Blog
{
public int Id { get; set; }
public BlogHeader? Header { get; set; } // Reference navigation to dependent
}
// Dependent (child)
public class BlogHeader
{
public int Id { get; set; }
public Blog Blog { get; set; } = null!; // Required reference navigation to principal
}
一対多リレーションシップとは異なり、一対一リレーションシップの依存側は、その 1 つ以上の主キー プロパティを 1 つ以上の外部キー プロパティとして使用できます。 多くの場合、これは PK 対 PK のリレーションシップと呼ばれます。 これは、プリンシパル型と依存型が主キーの型が同じ場合にのみ可能であり、依存側の主キーを null 許容にすることはできないため、結果のリレーションシップは常に必須になります。
規則によって外部キーが検出されない一対一リレーションシップは、リレーションシップのプリンシパル側と依存側を示すように構成する必要があります。 通常、これを行うには、HasForeignKey
を呼び出します。 次に例を示します。
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.HasOne(e => e.Header)
.WithOne(e => e.Blog)
.HasForeignKey<BlogHeader>();
}
ヒント
HasPrincipalKey
もこの目的で使用できますが、あまり一般的ではありません。
HasForeignKey
の呼び出しでプロパティを指定せず、主キーが適切である場合は、外部キーとして使われます。 リレーションシップのナビゲーション、外部キー、または必須とオプションの性質が規則によって検出されない場合は、これらの設定を明示的に構成できます。 次に例を示します。
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.HasOne(e => e.Header)
.WithOne(e => e.Blog)
.HasForeignKey<BlogHeader>(e => e.Id)
.IsRequired();
}
シャドウ外部キーがある必須の一対一
// Principal (parent)
public class Blog
{
public int Id { get; set; }
public BlogHeader? Header { get; set; } // Reference navigation to dependent
}
// Dependent (child)
public class BlogHeader
{
public int Id { get; set; }
public Blog Blog { get; set; } = null!; // Required reference navigation to principal
}
外部キーはデータベースでのリレーションシップの表現方法の詳細であり、純粋にオブジェクト指向の方法でリレーションシップを使うときは必要ないため、モデルに外部キー プロパティが必要ない場合があります。 ただし、エンティティがシリアル化される場合 (たとえば、ネットワーク経由で送信するため)、外部キー値は、エンティティがオブジェクト形式ではないときにリレーションシップ情報を正確に保持するための便利な方法になることがあります。 そのため、多くの場合、この目的のために外部キー プロパティを .NET 型で保持することは実用的です。 外部キーのプロパティはプライベートにすることができます。これは多くの場合、エンティティと一緒にその値を転送できるようにしながら、外部キーが公開されるのを防ぐための、適切な妥協案です。
前の例に続いて、この例では、依存エンティティ型から外部キー プロパティを削除します。 ただし、EF は、主キーを使うのではなく、シャドウ外部キー プロパティを int
型の BlogId
という名前で作成するよう指示されます。
ここで注意すべき重要な点は、C# の null 許容参照型が使われているため、外部キー プロパティが null 許容かどうか、したがってリレーションシップがオプションか必須かの判断には、依存からプリンシパルへのナビゲーションの null 値の許容が使われるということです。 null 許容参照型が使われていない場合は、シャドウ外部キー プロパティは既定で null 許容になり、リレーションシップは既定でオプションになります。 この場合は、IsRequired
を使ってシャドウ外部キー プロパティを強制的に null 非許容にして、リレーションシップを必須にします。
このリレーションシップも、プリンシパル側と依存側を示すための構成が必要です。
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.HasOne(e => e.Header)
.WithOne(e => e.Blog)
.HasForeignKey<BlogHeader>("BlogId");
}
リレーションシップのナビゲーション、外部キー、または必須とオプションの性質が規則によって検出されない場合は、これらの設定を明示的に構成できます。 次に例を示します。
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.HasOne(e => e.Header)
.WithOne(e => e.Blog)
.HasForeignKey<BlogHeader>("BlogId")
.IsRequired();
}
シャドウ外部キーがあるオプションの一対一
// Principal (parent)
public class Blog
{
public int Id { get; set; }
public BlogHeader? Header { get; set; } // Reference navigation to dependent
}
// Dependent (child)
public class BlogHeader
{
public int Id { get; set; }
public Blog? Blog { get; set; } // Optional reference navigation to principal
}
前の例と同様に、依存エンティティ型からは外部キー プロパティが削除されています。 ただし、前の例とは異なり、今度は、C# の null 許容参照型が使われていて、依存エンティティ型でのナビゲーションが null 許容であるため、外部キー プロパティは null 許容として作成されます。 これにより、リレーションシップはオプションになります。
C# の null 許容参照型が使われていない場合は、外部キー プロパティは既定で null 許容として作成されます。 つまり、自動的に作成されるシャドウ プロパティを持つリレーションシップは、既定でオプションになります。
前と同様に、このリレーションシップには、プリンシパル側と依存側を示すための構成が必要です。
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.HasOne(e => e.Header)
.WithOne(e => e.Blog)
.HasForeignKey<BlogHeader>("BlogId");
}
リレーションシップのナビゲーション、外部キー、または必須とオプションの性質が規則によって検出されない場合は、これらの設定を明示的に構成できます。 次に例を示します。
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.HasOne(e => e.Header)
.WithOne(e => e.Blog)
.HasForeignKey<BlogHeader>("BlogId")
.IsRequired(false);
}
プリンシパル側へのナビゲーションのない一対一
// Principal (parent)
public class Blog
{
public int Id { get; set; }
public BlogHeader? Header { get; set; } // Reference navigation to dependent
}
// Dependent (child)
public class BlogHeader
{
public int Id { get; set; }
public int BlogId { get; set; } // Required foreign key property
}
この例では、外部キー プロパティが再び導入されていますが、依存側でのナビゲーションは削除されています。
ヒント
ナビゲーションが 1 つだけのリレーションシップ (依存側からプリンシパル側、またはプリンシパル側から依存側のどちらか一方だけ) は、一方向リレーションシップと呼ばれます。
このリレーションシップは規則によって検出されます。これは、外部キーが検出され、それによって依存側がされるからです。 リレーションシップのナビゲーション、外部キー、または必須とオプションの性質が規則によって検出されない場合は、これらの設定を明示的に構成できます。 次に例を示します。
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.HasOne(e => e.Header)
.WithOne()
.HasForeignKey<BlogHeader>(e => e.BlogId)
.IsRequired();
}
WithOne
の呼び出しに引数がないことに注意してください。 これは、BlogHeader
から Blog
へのナビゲーションがないことを EF に伝える方法です。
ナビゲーションのないエンティティから構成が始まる場合は、リレーションシップの他の端にあるエンティティの型を、ジェネリック HasOne<>()
の呼び出しを使って明示的に指定する必要があります。 次に例を示します。
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<BlogHeader>()
.HasOne<Blog>()
.WithOne(e => e.Header)
.HasForeignKey<BlogHeader>(e => e.BlogId)
.IsRequired();
}
プリンシパル側へのナビゲーションがなく、シャドウ外部キーがある一対一
// Principal (parent)
public class Blog
{
public int Id { get; set; }
public BlogHeader? Header { get; set; } // Reference navigation to dependent
}
// Dependent (child)
public class BlogHeader
{
public int Id { get; set; }
}
この例では、外部キー プロパティと依存側でのナビゲーションの両方を削除することにより、前の 2 つの例を組み合わせます。
前と同様に、このリレーションシップには、プリンシパル側と依存側を示すための構成が必要です。
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.HasOne(e => e.Header)
.WithOne()
.HasForeignKey<BlogHeader>("BlogId")
.IsRequired();
}
必要に応じて IsRequired()
または IsRequired(false)
の適切な呼び出しを行い、さらに完全な構成を使って、ナビゲーションと外部キー名を明示的に構成できます。 次に例を示します。
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.HasOne(e => e.Header)
.WithOne()
.HasForeignKey<BlogHeader>("BlogId")
.IsRequired();
}
依存側へのナビゲーションのない一対一
// Principal (parent)
public class Blog
{
public int Id { get; set; }
}
// Dependent (child)
public class BlogHeader
{
public int Id { get; set; }
public int BlogId { get; set; } // Required foreign key property
public Blog Blog { get; set; } = null!; // Required reference navigation to principal
}
前の 2 つの例では、プリンシパル側から依存側へのナビゲーションはありましたが、依存側からプリンシパル側へのナビゲーションはありませんでした。 次の 2 つの例では、依存側にナビゲーションを再び導入しますが、代わりにプリンシパル側のナビゲーションを削除します。
規則により、EF はこれを一対多リレーションシップとして扱います。 一対一にするには、最小限の構成がいくつか必要です。
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<BlogHeader>()
.HasOne(e => e.Blog)
.WithOne();
}
ここでも、引数なしで WithOne()
を呼び出し、この方向のナビゲーションがないことを示していることに注意してください。
リレーションシップのナビゲーション、外部キー、または必須とオプションの性質が規則によって検出されない場合は、これらの設定を明示的に構成できます。 次に例を示します。
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<BlogHeader>()
.HasOne(e => e.Blog)
.WithOne()
.HasForeignKey<BlogHeader>(e => e.BlogId)
.IsRequired();
}
ナビゲーションのないエンティティから構成が始まる場合は、リレーションシップの他の端にあるエンティティの型を、ジェネリック HasOne<>()
の呼び出しを使って明示的に指定する必要があります。 次に例を示します。
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.HasOne<BlogHeader>()
.WithOne(e => e.Blog)
.HasForeignKey<BlogHeader>(e => e.BlogId)
.IsRequired();
}
ナビゲーションなしの一対一
場合によっては、ナビゲーションのないリレーションシップを構成すると便利なことがあります。 このようなリレーションシップは、外部キーの値を直接変更することによってのみ操作できます。
// Principal (parent)
public class Blog
{
public int Id { get; set; }
}
// Dependent (child)
public class BlogHeader
{
public int Id { get; set; }
public int BlogId { get; set; } // Required foreign key property
}
2 つの型が関連していることを示すナビゲーションがないため、このリレーションシップは規則によって検出されません。 OnModelCreating
で明示的に構成できます。 次に例を示します。
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.HasOne<BlogHeader>()
.WithOne();
}
この構成では、BlogHeader.BlogId
プロパティは規則によって引き続き外部キーとして検出され、外部キー プロパティが null 許容ではないため、リレーションシップは "必須" です。 外部キー プロパティを null 許容にすることで、リレーションシップを "オプション" にできます。
このリレーションシップのより完全な明示的な構成は次のとおりです。
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.HasOne<BlogHeader>()
.WithOne()
.HasForeignKey<BlogHeader>(e => e.BlogId)
.IsRequired();
}
代替キーがある一対一
ここまでのすべての例では、依存側の外部キー プロパティは、プリンシパル側の主キー プロパティに制約されています。 代わりに、外部キーを別のプロパティに制約でき、これによりそれはプリンシパル エンティティ型の代替キーになります。 次に例を示します。
// Principal (parent)
public class Blog
{
public int Id { get; set; }
public int AlternateId { get; set; } // Alternate key as target of the BlogHeader.BlogId foreign key
public BlogHeader? Header { get; set; } // Reference navigation to dependent
}
// Dependent (child)
public class BlogHeader
{
public int Id { get; set; }
public int BlogId { get; set; } // Required foreign key property
public Blog Blog { get; set; } = null!; // Required reference navigation to principal
}
EF は常に規則によって主キーへのリレーションシップを作成するため、このリレーションシップは規則によって検出されません。 OnModelCreating
で HasPrincipalKey
の呼び出しを使って明示的に構成できます。 次に例を示します。
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.HasOne(e => e.Header)
.WithOne(e => e.Blog)
.HasPrincipalKey<Blog>(e => e.AlternateId);
}
HasPrincipalKey
を他の呼び出しと組み合わせて、ナビゲーション、外部キー プロパティ、必須とオプションの性質を明示的に構成できます。 次に例を示します。
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.HasOne(e => e.Header)
.WithOne(e => e.Blog)
.HasPrincipalKey<Blog>(e => e.AlternateId)
.HasForeignKey<BlogHeader>(e => e.BlogId)
.IsRequired();
}
複合外部キーがある一対一
これまでのすべての例では、プリンシパル側の主キー プロパティまたは代替キー プロパティは 1 つのプロパティで構成されていました。 主キーまたは代替キーは、複数のプロパティで構成することもできます。これらは "複合キー" と呼ばれます。 リレーションシップのプリンシパル側に複合キーがある場合、依存側の外部キーも同じ数のプロパティを持つ複合キーである必要があります。 次に例を示します。
// Principal (parent)
public class Blog
{
public int Id1 { get; set; } // Composite key part 1
public int Id2 { get; set; } // Composite key part 2
public BlogHeader? Header { get; set; } // Reference navigation to dependent
}
// Dependent (child)
public class BlogHeader
{
public int Id { get; set; }
public int BlogId1 { get; set; } // Required foreign key property part 1
public int BlogId2 { get; set; } // Required foreign key property part 2
public Blog Blog { get; set; } = null!; // Required reference navigation to principal
}
このリレーションシップは、規則によって検出されます。 ただし、複合キーは自動的に検出されないので、複合キーが明示的に構成されている場合にのみ検出されます。 次に例を示します。
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.HasKey(e => new { e.Id1, e.Id2 });
}
重要
複合外部キーの値は、そのプロパティの値のいずれかが null の場合、null
と見なされます。 1 つのプロパティが null でそれ以外は null ではない複合外部キーは、同じ値を持つ主キーまたは代替キーと一致するものと見なされません。 どちらも null
と見なされます。
HasForeignKey
と HasPrincipalKey
の両方を使って、複数のプロパティを持つキーを明示的に指定できます。 次に例を示します。
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>(
nestedBuilder =>
{
nestedBuilder.HasKey(e => new { e.Id1, e.Id2 });
nestedBuilder.HasOne(e => e.Header)
.WithOne(e => e.Blog)
.HasPrincipalKey<Blog>(e => new { e.Id1, e.Id2 })
.HasForeignKey<BlogHeader>(e => new { e.BlogId1, e.BlogId2 })
.IsRequired();
});
}
ヒント
上のコードでは、HasKey
と HasOne
の呼び出しが、入れ子になったビルダーにグループ化されています。 入れ子になったビルダーを使うと、同じエンティティ型に対して Entity<>()
を複数回呼び出す必要がなくなりますが、機能的には Entity<>()
を複数回呼び出すのと同じです。
連鎖削除のない必須の一対一
// Principal (parent)
public class Blog
{
public int Id { get; set; }
public BlogHeader? Header { get; set; } // Reference navigation to dependent
}
// Dependent (child)
public class BlogHeader
{
public int Id { get; set; }
public int BlogId { get; set; } // Required foreign key property
public Blog Blog { get; set; } = null!; // Required reference navigation to principal
}
規則により、必須リレーションシップは連鎖削除に構成されています。 これは、プリンシパルが削除されると、依存側がデータベースに存在できなくなるためです。 存在できなくなった依存行を自動的に削除するのではなく、エラーを生成する (通常はアプリケーションをクラッシュさせる) ようにデータベースを構成することができます。 これにはいくつかの構成が必要です。
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.HasOne(e => e.Header)
.WithOne(e => e.Blog)
.OnDelete(DeleteBehavior.Restrict);
}
自己参照の一対一
これまでのすべての例では、プリンシパル エンティティ型と依存エンティティ型は異なっていました。 そうなっていなければならないわけではありません。 たとえば、次の型では、各 Person
は必要に応じて別の Person
と関連付けられています。
public class Person
{
public int Id { get; set; }
public int? HusbandId { get; set; } // Optional foreign key property
public Person? Husband { get; set; } // Optional reference navigation to principal
public Person? Wife { get; set; } // Reference navigation to dependent
}
このリレーションシップは、規則によって検出されます。 リレーションシップのナビゲーション、外部キー、または必須とオプションの性質が規則によって検出されない場合は、これらの設定を明示的に構成できます。 次に例を示します。
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Person>()
.HasOne(e => e.Husband)
.WithOne(e => e.Wife)
.HasForeignKey<Person>(e => e.HusbandId)
.IsRequired(false);
}
注意
一対一の自己参照リレーションシップの場合、プリンシパルと依存のエンティティ型が同じであるため、どちらの型に外部キーが含まれるかを指定しても、依存側は明確になりません。 この場合、HasOne
に指定したナビゲーションで依存からプリンシパルへを指し、WithOne
に指定したナビゲーションで、プリンシパルから依存へを指します。
.NET