Schatten- und Indexereigenschaften

Schatteneigenschaften sind Eigenschaften, die nicht in Ihrer .NET-Entitätsklasse definiert sind, aber für diesen Entitätstyp im EF Core-Modell definiert sind. Wert und Zustand dieser Eigenschaften werden ausschließlich im Change Tracker beibehalten. Schatteneigenschaften sind nützlich, wenn sich Daten in der Datenbank befinden, die nicht für die zugeordneten Entitätstypen verfügbar gemacht werden sollten.

Indexereigenschaften sind Entitätstypeigenschaften, die von einem Indexer in der .NET-Entitätsklasse unterstützt werden. Auf sie kann mithilfe des Indexers in den .NET-Klasseninstanzen zugegriffen werden. Außerdem können Sie dem Entitätstyp zusätzliche Eigenschaften hinzufügen, ohne die CLR-Klasse zu ändern.

Fremdschlüsselschatteneigenschaften

Schatteneigenschaften werden am häufigsten für Fremdschlüsseleigenschaften verwendet, bei denen sie dem Modell durch Konvention hinzugefügt werden, wenn keine Fremdschlüsseleigenschaft durch Konvention gefunden oder explizit konfiguriert wurde. Die Beziehung wird durch Navigationseigenschaften dargestellt, aber in der Datenbank wird sie durch eine Fremdschlüsseleinschränkung erzwungen, und der Wert für die Fremdschlüsselspalte wird in der entsprechenden Schatteneigenschaft gespeichert.

Die -Eigenschaft wird benannt <navigation property name><principal key property name> (die Navigation der abhängigen Entität, die auf die Prinzipalentität verweist, wird für die Benennung verwendet). Wenn der Name der Prinzipalschlüsseleigenschaft mit dem Namen der Navigationseigenschaft beginnt, lautet <principal key property name>der Name nur . Wenn keine Navigationseigenschaft für die abhängige Entität vorhanden ist, wird der Name des Prinzipaltyps an seiner Stelle verwendet.

Die folgende Codeauflistung führt beispielsweise dazu, dass eine BlogId Schatteneigenschaft in die Post Entität eingeführt wird:

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

Konfigurieren von Schatteneigenschaften

Sie können die Fluent-API verwenden, um Schatteneigenschaften zu konfigurieren. Nachdem Sie die Zeichenfolgenüberladung von Property<TProperty>(String)aufgerufen haben, können Sie alle Konfigurationsaufrufe verketten, die Sie für andere Eigenschaften verwenden würden. Im folgenden Beispiel wird eine Schatteneigenschaft erstellt, da Blog keine CLR-Eigenschaft namens vorhanden LastUpdatedist:

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

Wenn der für die Property -Methode angegebene Name mit dem Namen einer vorhandenen Eigenschaft (einer Schatteneigenschaft oder einer für die Entitätsklasse definierten Eigenschaft) übereinstimmt, konfiguriert der Code diese vorhandene Eigenschaft, anstatt eine neue Schatteneigenschaft einzuführen.

Zugreifen auf Schatteneigenschaften

Shadow-Eigenschaftswerte können über die ChangeTracker API abgerufen und geändert werden:

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

Schatteneigenschaften können in LINQ-Abfragen über die EF.Property statische Methode referenziert werden:

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

Auf Schatteneigenschaften kann nach einer No-Tracking-Abfrage nicht zugegriffen werden, da die zurückgegebenen Entitäten nicht vom Änderungsnachverfolgung nachverfolgt werden.

Konfigurieren von Indexereigenschaften

Sie können die Fluent-API verwenden, um Indexereigenschaften zu konfigurieren. Nachdem Sie die -Methode IndexerPropertyaufgerufen haben, können Sie alle Konfigurationsaufrufe verketten, die Sie für andere Eigenschaften verwenden würden. Im folgenden Beispiel ist ein Indexer definiert, Blog der zum Erstellen einer Indexereigenschaft verwendet wird.

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

Wenn der für die IndexerProperty -Methode angegebene Name mit dem Namen einer vorhandenen Indexereigenschaft übereinstimmt, konfiguriert der Code diese vorhandene Eigenschaft. Wenn der Entitätstyp über eine Eigenschaft verfügt, die durch eine Eigenschaft für die Entitätsklasse unterstützt wird, wird eine Ausnahme ausgelöst, da auf Indexereigenschaften nur über den Indexer zugegriffen werden darf.

Indexereigenschaften können in LINQ-Abfragen über die EF.Property statische Methode wie oben gezeigt oder mithilfe der CLR-Indexereigenschaft referenziert werden.

Entitätstypen des Eigenschaftenbehälters

Entitätstypen, die nur Indexereigenschaften enthalten, werden als Eigenschaftenbehälterentitätstypen bezeichnet. Diese Entitätstypen verfügen nicht über Schatteneigenschaften, und EF erstellt stattdessen Indexereigenschaften. Derzeit wird nur Dictionary<string, object> als Entitätstyp des Eigenschaftenbehälters unterstützt. Er muss als Entitätstyp vom typ shared mit einem eindeutigen Namen konfiguriert werden, und die entsprechende DbSet Eigenschaft muss mithilfe eines Aufrufs Set implementiert werden.

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

Entitätstypen des Eigenschaftenbehälters können überall dort verwendet werden, wo ein normaler Entitätstyp verwendet wird, einschließlich als unternehmenseigener Entitätstyp. Sie haben jedoch bestimmte Einschränkungen: