注
この機能は、クエリの種類の名前の下に追加されました。 その後、キーレス エンティティ型に名前が変更されました。
EF Core モデルには、通常のエンティティ型に加えて、 キーなしのエンティティ型を含めることができます。これを使用して、キー値を含まないデータに対してデータベース クエリを実行できます。
キーを持たないエンティティ型の定義
キーレス エンティティ型は、次のように定義できます。
[Keyless]
public class BlogPostsCount
{
public string BlogName { get; set; }
public int PostCount { get; set; }
}
キーレス エンティティ型の特性
キーレス エンティティ型は、継承マッピングやナビゲーション プロパティなど、通常のエンティティ型と同じマッピング機能の多くをサポートします。 リレーショナル ストアでは、fluent API メソッドまたはデータ注釈を使用して、ターゲット データベース オブジェクトと列を構成できます。
ただし、これらは次の点で通常のエンティティ型とは異なります。
- キーを定義できません。
- DbContext の変更は追跡されないため、データベースに対して挿入、更新、削除されることはありません。
- 慣習によって発見されることは決してありません。
- ナビゲーション マッピング機能のサブセットのみをサポートします。具体的には次のとおりです。
- これらは、リレーションシップの主要な終わりとして機能しない場合があります。
- 所有エンティティへのナビゲーションがない可能性があります
- 通常のエンティティを指す参照ナビゲーション プロパティのみを含めることができます。
- エンティティには、キーレス エンティティ型へのナビゲーション プロパティを含めることはできません。
-
[Keyless]
データ注釈または.HasNoKey()
メソッド呼び出しを使用して構成する必要があります。 - 定義クエリにマップできます。 定義クエリは、キーレス エンティティ型のデータ ソースとして機能するモデルで宣言されたクエリです。
- 階層を持つことができますが、TPH としてマップする必要があります。
- テーブル分割またはエンティティ分割を使用できません。
使用シナリオ
キーレス エンティティ型の主な使用シナリオの一部を次に示します。
- SQL クエリの戻り値の型として機能します。
- 主キーを含まないデータベース ビューへのマッピング。
- 主キーが定義されていないテーブルへのマッピング。
- モデルで定義されているクエリへのマッピング。
データベース オブジェクトへのマッピング
キーレス エンティティ型をデータベース オブジェクトにマッピングするには、 ToTable
または fluent API ToView
使用します。 EF Core の観点からは、このメソッドで指定されたデータベース オブジェクトは ビューです。つまり、このオブジェクトは読み取り専用クエリ ソースとして扱われ、更新、挿入、または削除の操作のターゲットにすることはできません。 ただし、これは、データベース オブジェクトが実際にはデータベース ビューである必要があることを意味するわけではありません。 または、読み取り専用として扱われるデータベース テーブルを指定することもできます。 逆に、通常のエンティティ型の場合、EF Core では、 ToTable
メソッドで指定されたデータベース オブジェクトを テーブルとして扱うことができると想定しています。つまり、クエリ ソースとして使用できるだけでなく、更新、削除、挿入の操作によっても使用できます。 実際には、 ToTable
でデータベース ビューの名前を指定できます。ビューがデータベースで更新可能に構成されている限り、すべてが正常に動作します。
例
次の例は、キーなしのエンティティ型を使用してデータベース ビューにクエリを実行する方法を示しています。
ヒント
この記事の サンプル は、GitHub で確認できます。
まず、単純なブログと投稿のモデルを定義します。
public class Blog
{
public int BlogId { get; set; }
public string Name { get; set; }
public string Url { get; set; }
public ICollection<Post> Posts { get; set; }
}
public class Post
{
public int PostId { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public int BlogId { get; set; }
}
次に、各ブログに関連付けられている投稿の数を照会できる単純なデータベース ビューを定義します。
await db.Database.ExecuteSqlRawAsync(
@"CREATE VIEW View_BlogPostCounts AS
SELECT b.Name, Count(p.PostId) as PostCount
FROM Blogs b
JOIN Posts p on p.BlogId = b.BlogId
GROUP BY b.Name");
次に、データベース ビューの結果を保持するクラスを定義します。
public class BlogPostsCount
{
public string BlogName { get; set; }
public int PostCount { get; set; }
}
次に、 API を使用して HasNoKey
でキーレス エンティティ型を構成します。
Fluent 構成 API を使用して、キーレス エンティティ型のマッピングを構成します。
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder
.Entity<BlogPostsCount>(
eb =>
{
eb.HasNoKey();
eb.ToView("View_BlogPostCounts");
eb.Property(v => v.BlogName).HasColumnName("Name");
});
}
次に、DbContext
を含むようにDbSet<T>
を構成します。
public DbSet<BlogPostsCount> BlogPostCounts { get; set; }
最後に、標準の方法でデータベース ビューに対してクエリを実行できます。
var postCounts = await db.BlogPostCounts.ToListAsync();
foreach (var postCount in postCounts)
{
Console.WriteLine($"{postCount.BlogName} has {postCount.PostCount} posts.");
Console.WriteLine();
}
ヒント
この型に対するクエリのルートとして機能するコンテキスト レベルのクエリ プロパティ (DbSet) も定義されていることに注意してください。
ヒント
メモリ内プロバイダーを使用してビューにマップされたキーレス エンティティ型をテストするには、 ToInMemoryQueryを使用してクエリにマップします。 詳細については、 メモリ内プロバイダーのドキュメント を参照してください。
.NET