次の方法で共有


シャドウプロパティとインデクサープロパティ

シャドウ プロパティは、.NET エンティティ クラスでは定義されていないが、EF Core モデルでそのエンティティ型に対して定義されているプロパティです。 これらのプロパティの値と状態は、変更トラッカーで純粋に維持されます。 シャドウ プロパティは、マップされたエンティティ型で公開すべきでないデータがデータベースに存在する場合に便利です。

インデクサー プロパティはエンティティ型プロパティであり、.NET エンティティ クラスの インデクサー によってサポートされます。 これらは、.NET クラス インスタンスのインデクサーを使用してアクセスできます。 また、CLR クラスを変更せずに、エンティティ型にプロパティを追加することもできます。

外部キーシャドウプロパティ

シャドウ プロパティは通常、外部キー プロパティに使用され、規則によって外部キー プロパティが見つからない場合や明示的に構成されていない場合に、規則によってモデルに追加されます。 リレーションシップはナビゲーション プロパティによって表されますが、データベースでは外部キー制約によって適用され、外部キー列の値は対応するシャドウ プロパティに格納されます。

プロパティには <navigation property name><principal key property name> という名前が付けられます (プリンシパル エンティティを指す依存エンティティのナビゲーションが名前付けに使用されます)。 プリンシパル キー プロパティ名がナビゲーション プロパティの名前で始まる場合、名前は <principal key property name>されます。 依存エンティティにナビゲーション プロパティがない場合は、プライマリ キーまたは代替キー プロパティ名と連結されたプリンシパル型名が、 <principal type name><principal key property name>の場所で使用されます。

たとえば、次のコード 一覧では、BlogId エンティティにPostシャドウ プロパティが導入されます。

internal class MyContext : DbContext
{
    public DbSet<Blog> Blogs { get; set; }
    public DbSet<Post> Posts { get; set; }
}

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; }

    // Since there is no CLR property which holds the foreign
    // key for this relationship, a shadow property is created.
    public Blog Blog { get; set; }
}

シャドウ プロパティの構成

Fluent API を使用してシャドウ プロパティを構成できます。 Property<TProperty>(String)の文字列オーバーロードを呼び出したら、他のプロパティに対して行う構成呼び出しをチェーンできます。 次の例では、 Blog には LastUpdated という CLR プロパティがないため、シャドウ プロパティが作成されます。

internal class MyContext : DbContext
{
    public DbSet<Blog> Blogs { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Blog>()
            .Property<DateTime>("LastUpdated");
    }
}

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

Property メソッドに指定された名前が既存のプロパティの名前 (シャドウ プロパティまたはエンティティ クラスで定義されている名前) と一致する場合、コードは新しいシャドウ プロパティを導入するのではなく、その既存のプロパティを構成します。

シャドウ プロパティへのアクセス

シャドウ プロパティの値は、 ChangeTracker API を使用して取得および変更できます。

context.Entry(myBlog).Property("LastUpdated").CurrentValue = DateTime.Now;

シャドウ プロパティは、 EF.Property 静的メソッドを使用して LINQ クエリで参照できます。

var blogs = context.Blogs
    .OrderBy(b => EF.Property<DateTime>(b, "LastUpdated"));

返されるエンティティは変更トラッカーによって追跡されないため、追跡なしのクエリの後にシャドウ プロパティにアクセスできません。

インデクサーのプロパティの構成

Fluent API を使用してインデクサーのプロパティを構成できます。 メソッド IndexerPropertyを呼び出したら、他のプロパティに対して行う構成呼び出しをチェーンできます。 次の例では、 Blog にはインデクサーが定義されており、インデクサー プロパティの作成に使用されます。

internal class MyContext : DbContext
{
    public DbSet<Blog> Blogs { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Blog>().IndexerProperty<DateTime>("LastUpdated");
    }
}

public class Blog
{
    private readonly Dictionary<string, object> _data = new Dictionary<string, object>();
    public int BlogId { get; set; }

    public object this[string key]
    {
        get => _data[key];
        set => _data[key] = value;
    }
}

IndexerProperty メソッドに指定された名前が既存のインデクサー プロパティの名前と一致する場合、コードはその既存のプロパティを構成します。 エンティティ型にプロパティがあり、エンティティ クラスのプロパティによってサポートされている場合、インデクサー プロパティにはインデクサーを介してのみアクセスする必要があるため、例外がスローされます。

上記のように、 EF.Property 静的メソッドを使用するか、CLR インデクサー プロパティを使用して、LINQ クエリでインデクサー プロパティを参照できます。

プロパティ バッグ エンティティの種類

インデクサー プロパティのみを含むエンティティ型は、プロパティ バッグ エンティティ型と呼ばれます。 これらのエンティティ型にはシャドウ プロパティがなく、代わりに EF によってインデクサー プロパティが作成されます。 現在、プロパティ バッグ エンティティ型としてサポートされているのは、 Dictionary<string, object> のみです。 一意の名前を持つ 共有型エンティティ型 として構成する必要があり、対応する 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");
            });
    }
}

プロパティ バッグ エンティティ型は、所有エンティティ型など、通常のエンティティ型が使用される場所であればどこでも使用できます。 ただし、次のような制限があります。