次の方法で共有


エンティティの種類

コンテキストに型の DbSet を含めると、それが EF Core のモデルに含まれることを意味します。通常、このような型はエンティティと見な されます。 EF Core では、データベースとの間でエンティティ インスタンスの読み取りと書き込みを行うことができます。リレーショナル データベースを使用している場合、EF Core は移行を介してエンティティのテーブルを作成できます。

型をモデルに含める

慣例により、コンテキスト上の DbSet プロパティで公開される型は、エンティティとしてモデルに含まれます。 他の検出されたエンティティ型のナビゲーション プロパティを再帰的に調べて検出される型と同様に、 OnModelCreating メソッドで指定されたエンティティ型も含まれます。

以下のコード サンプルでは、すべての型が含まれています。

  • Blog は、コンテキストの DbSet プロパティで公開されるために含まれます。
  • Post は、 Blog.Posts ナビゲーション プロパティを介して検出されるために含まれます。
  • AuditEntry これは、 OnModelCreatingで指定されているためです。
internal class MyContext : DbContext
{
    public DbSet<Blog> Blogs { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<AuditEntry>();
    }
}

public class Blog
{
    public int BlogId { get; set; }
    public string Url { get; set; }

    public List<Post> Posts { get; set; }
}

public class Post
{
    public int PostId { get; set; }
    public string Title { get; set; }
    public string Content { get; set; }

    public Blog Blog { get; set; }
}

public class AuditEntry
{
    public int AuditEntryId { get; set; }
    public string Username { get; set; }
    public string Action { get; set; }
}

モデルから型を除外する

型をモデルに含めない場合は、それを除外できます。

[NotMapped]
public class BlogMetadata
{
    public DateTime LoadedFromDatabase { get; set; }
}

移行からの除外

同じエンティティ型を複数の DbContext 型にマップすると便利な場合があります。 これは特に、 境界付きコンテキストを使用する場合に当てはまります。このコンテキストでは、境界付けられたコンテキストごとに異なる DbContext 型が使用されるのが一般的です。

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<IdentityUser>()
        .ToTable("AspNetUsers", t => t.ExcludeFromMigrations());
}

この構成の移行では、 AspNetUsers テーブルは作成されませんが、 IdentityUser はまだモデルに含まれており、通常どおりに使用できます。

移行を使用してテーブルの管理を再度開始する必要がある場合は、 AspNetUsers が除外されない新しい移行を作成する必要があります。 次の移行には、テーブルに加えられた変更が含まれるようになります。

テーブル名

慣例により、各エンティティ型は、エンティティを公開する DbSet プロパティと同じ名前のデータベース テーブルにマップするように設定されます。 指定されたエンティティに DbSet が存在しない場合は、クラス名が使用されます。

テーブル名は手動で構成できます。

[Table("blogs")]
public class Blog
{
    public int BlogId { get; set; }
    public string Url { get; set; }
}

テーブル スキーマ

リレーショナル データベースを使用する場合、テーブルは規則に従ってデータベースの既定のスキーマに作成されます。 たとえば、Microsoft SQL Server では dbo スキーマが使用されます (SQLite ではスキーマはサポートされていません)。

特定のスキーマで作成するテーブルは、次のように構成できます。

[Table("blogs", Schema = "blogging")]
public class Blog
{
    public int BlogId { get; set; }
    public string Url { get; set; }
}

各テーブルのスキーマを指定するのではなく、fluent API を使用してモデル レベルで既定のスキーマを定義することもできます。

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.HasDefaultSchema("blogging");
}

既定のスキーマを設定すると、シーケンスなどの他のデータベース オブジェクトにも影響します。

マッピングの表示

エンティティ型は、Fluent API を使用してデータベース ビューにマップできます。

EF は、参照先のビューがデータベースに既に存在することを前提とします。移行では自動的には作成されません。

modelBuilder.Entity<Blog>()
    .ToView("blogsView", schema: "blogging");

ビューにマッピングすると、既定のテーブル マッピングが削除されますが、エンティティ型を明示的にテーブルにマップすることもできます。 この場合、ビュー マッピングはクエリに使用され、テーブル マッピングは更新に使用されます。

ヒント

メモリ内プロバイダーを使用してビューにマップされたキーレス エンティティ型をテストするには、 ToInMemoryQueryを使用してクエリにマップします。 詳細については、 メモリ内プロバイダーのドキュメント を参照してください。

テーブル値関数のマッピング

エンティティ型は、データベース内のテーブルではなく、テーブル値関数 (TVF) にマップできます。 これを説明するために、複数の投稿を含むブログを表す別のエンティティを定義しましょう。 この例では、エンティティは キーレスですが、そうである必要はありません。

public class BlogWithMultiplePosts
{
    public string Url { get; set; }
    public int PostCount { get; set; }
}

次に、次のテーブル値関数をデータベースに作成します。この関数は、複数の投稿を含むブログと、これらの各ブログに関連付けられている投稿の数のみを返します。

CREATE FUNCTION dbo.BlogsWithMultiplePosts()
RETURNS TABLE
AS
RETURN
(
    SELECT b.Url, COUNT(p.BlogId) AS PostCount
    FROM Blogs AS b
    JOIN Posts AS p ON b.BlogId = p.BlogId
    GROUP BY b.BlogId, b.Url
    HAVING COUNT(p.BlogId) > 1
)

これで、エンティティ BlogWithMultiplePosts を次の方法でこの関数にマップできます。

modelBuilder.Entity<BlogWithMultiplePosts>().HasNoKey().ToFunction("BlogsWithMultiplePosts");

エンティティをテーブル値関数にマップするには、関数をパラメーターなしにする必要があります。

従来、エンティティ プロパティは、TVF によって返される一致する列にマップされます。 TVF によって返される列の名前がエンティティ プロパティと異なる場合は、通常のテーブルにマッピングする場合と同様に、 HasColumnName メソッドを使用してエンティティの列を構成できます。

エンティティ型がテーブル値関数にマップされると、クエリは次のようになります。

var query = from b in context.Set<BlogWithMultiplePosts>()
            where b.PostCount > 3
            select new { b.Url, b.PostCount };

次の SQL を生成します。

SELECT [b].[Url], [b].[PostCount]
FROM [dbo].[BlogsWithMultiplePosts]() AS [b]
WHERE [b].[PostCount] > 3

テーブルのコメント

データベース テーブルに設定される任意のテキスト コメントを設定して、データベース内のスキーマを文書化できます。

[Comment("Blogs managed on the website")]
public class Blog
{
    public int BlogId { get; set; }
    public string Url { get; set; }
}

共有型エンティティ型

同じ CLR 型を使用するエンティティ型は、共有型エンティティ型と呼ばれます。 これらのエンティティ型は、CLR 型に加えて、共有型エンティティ型が使用されるたびに指定する必要がある一意の名前で構成する必要があります。 つまり、対応する DbSet プロパティは、 Set 呼び出しを使用して実装する必要があります。

internal class MyContext : DbContext
{
    public DbSet<Dictionary<string, object>> Blogs => Set<Dictionary<string, object>>("Blog");

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.SharedTypeEntity<Dictionary<string, object>>(
            "Blog", bb =>
            {
                bb.Property<int>("BlogId");
                bb.Property<string>("Url");
                bb.Property<DateTime>("LastUpdated");
            });
    }
}