リレーションシップのマッピング属性 (データ注釈)
マッピング属性は、モデル構築規則によって検出された構成を変更またはオーバーライドするために使われます。 マッピング属性によって実行された構成自体を、OnModelCreating
で使われるモデル構築 API によってオーバーライドできます。
重要
このドキュメントでは、リレーションシップ構成のコンテキストでのマッピング属性についてのみ説明します。 マッピング属性の他の用途については、より広範なモデリングのドキュメントの関連セクションをご覧ください。
ヒント
以下のコードは MappingAttributes.cs にあります。
マッピング属性を取得する場所
多くのマッピング属性は、System.ComponentModel.DataAnnotations と System.ComponentModel.DataAnnotations.Schema 名前空間から取得されます。 これらの名前空間の属性は、サポートされているすべてのバージョンの .NET の基本フレームワークの一部として含まれるため、追加の NuGet パッケージをインストールする必要はありません。 これらのマッピング属性は、一般に "データ注釈" と呼ばれ、EF Core、EF6、ASP.NET Core MVC などのさまざまなフレームワークで使われます。 これらは検証にも使われます。
多くのテクノロジで、マッピングと検証の両方にデータ注釈が使われているため、テクノロジによってセマンティクスが異なるようになっています。 EF Core 用に設計された新しいマッピング属性はすべて、EF Core に固有であるため、シンプルで明確なセマンティクスと使い方が維持されています。 これらの属性は、Microsoft.EntityFrameworkCore.Abstractions NuGet パッケージに含まれています。 メインの Microsoft.EntityFrameworkCore パッケージまたは関連付けられているデータベース プロバイダー パッケージの 1 つが使われるときは常に、このパッケージが依存関係として含まれます。 ただし、Abstractions パッケージは、すべての EF Core とその依存関係を取り込むことなく、アプリケーション コードから直接参照できる軽量パッケージです。
RequiredAttribute
RequiredAttribute は、プロパティを null
にできないことを示すために、プロパティに適用されます。 リレーションシップのコンテキストの場合、外部キー プロパティでは [Required]
が通常使われます。 これを行うと、外部キーが null 非許容になり、リレーションシップが必須になります。 たとえば、次の型では、Post.BlogId
プロパティは null 非許容になり、リレーションシップが必須になります。
public class Blog
{
public string Id { get; set; }
public List<Post> Posts { get; } = new();
}
public class Post
{
public int Id { get; set; }
[Required]
public string BlogId { get; set; }
public Blog Blog { get; init; }
}
注意
C# の null 許容参照型を使うと、この例の BlogId
プロパティは既に null 非許容であるため、[Required]
属性への影響はないことを意味します。
依存ナビゲーションに配置された [Required]
には、同じ効果があります。 つまり、外部キーを null 非許容にし、それによってリレーションシップを必須にします。 次に例を示します。
public class Blog
{
public string Id { get; set; }
public List<Post> Posts { get; } = new();
}
public class Post
{
public int Id { get; set; }
public string BlogId { get; set; }
[Required]
public Blog Blog { get; init; }
}
[Required]
が依存ナビゲーションで検出され、外部キー プロパティがシャドウ状態である場合、シャドウ プロパティは null 非許容にされ、それによってリレーションシップが必須にされます。 次に例を示します。
public class Blog
{
public string Id { get; set; }
public List<Post> Posts { get; } = new();
}
public class Post
{
public int Id { get; set; }
[Required]
public Blog Blog { get; init; }
}
注意
リレーションシップのプリンシパル ナビゲーション側で [Required]
を使っても効果はありません。
ForeignKeyAttribute
ForeignKeyAttribute は、外部キー プロパティとそのナビゲーションを接続するために使われます。 [ForeignKey]
は、依存ナビゲーションの名前を使って外部キー プロパティに配置できます。 次に例を示します。
public class Blog
{
public string Id { get; set; }
public List<Post> Posts { get; } = new();
}
public class Post
{
public int Id { get; set; }
[ForeignKey(nameof(Blog))]
public string BlogKey { get; set; }
public Blog Blog { get; init; }
}
または、外部キーとして使うプロパティの名前を使うと、依存ナビゲーションまたはプリンシパル ナビゲーションのどちらにでも [ForeignKey]
を配置できます。 次に例を示します。
public class Blog
{
public string Id { get; set; }
public List<Post> Posts { get; } = new();
}
public class Post
{
public int Id { get; set; }
public string BlogKey { get; set; }
[ForeignKey(nameof(BlogKey))]
public Blog Blog { get; init; }
}
[ForeignKey]
がナビゲーションに配置されていて、指定された名前がどのプロパティ名とも一致しない場合は、その名前を持つシャドウ プロパティが外部キーとして機能するように作成されます。 次に例を示します。
public class Blog
{
public string Id { get; set; }
public List<Post> Posts { get; } = new();
}
public class Post
{
public int Id { get; set; }
[ForeignKey("BlogKey")]
public Blog Blog { get; init; }
}
InversePropertyAttribute
InversePropertyAttribute は、ナビゲーションをその逆のものと接続するために使われます。 たとえば、次のエンティティ型では、Blog
と Post
の間に 2 つのリレーションシップがあります。 構成がないと、EF 規則は、2 つの型の間でペアにする必要があるナビゲーションを決定できません。 ペアになっているナビゲーションのいずれかに [InverseProperty]
を追加すると、このあいまいさが解決され、EF はモデルを構築できるようになります。
public class Blog
{
public int Id { get; set; }
[InverseProperty("Blog")]
public List<Post> Posts { get; } = new();
public int FeaturedPostId { get; set; }
public Post FeaturedPost { get; set; }
}
public class Post
{
public int Id { get; set; }
public int BlogId { get; set; }
public Blog Blog { get; init; }
}
重要
[InverseProperty]
は、同じ型の間に複数のリレーションシップがある場合にのみ必要です。 リレーションシップが 1 つのときは、2 つのナビゲーションが自動的にペアになります。
DeleteBehaviorAttribute
規則により、EF では、オプションのリレーションシップに ClientSetNull
DeleteBehavior が使われ、必須のリレーションシップには Cascade
動作が使われます。 これは、リレーションシップのいずれかのナビゲーションに DeleteBehaviorAttribute を配置することで変更できます。 次に例を示します。
public class Blog
{
public int Id { get; set; }
public List<Post> Posts { get; } = new();
}
public class Post
{
public int Id { get; set; }
public int BlogId { get; set; }
[DeleteBehavior(DeleteBehavior.Restrict)]
public Blog Blog { get; init; }
}
カスケード動作について詳しくは、「連鎖削除」をご覧ください。
.NET