Schlüssellose Entitätstypen
Hinweis
Diese Funktion wurde unter dem Namen der Abfragetypen hinzugefügt. Sie wurde später in schlüssellose Entitätstypen umbenannt.
Zusätzlich zu regulären Entitätstypen kann ein EF Core-Modell schlüssellose Entitätstypenenthalten, die verwendet werden können, um Datenbankabfragen für Daten auszuführen, die keine Schlüsselwerte enthalten.
Definieren schlüsselloser Entitätstypen
Schlüssellose Entitätstypen können wie folgt definiert werden:
[Keyless]
public class BlogPostsCount
{
public string BlogName { get; set; }
public int PostCount { get; set; }
}
Merkmale von Schlüssellosen Entitätstypen
Schlüssellose Entitätstypen unterstützen viele der gleichen Mappingfähigkeiten wie normale Entitätstypen, z. B. Vererbungsmapping und Navigationseigenschaften. Bei verknüpften Speichern können sie die Objekte und Spalten der Zieldatenbank über flüssige API-Methoden oder Datenkommentare konfigurieren.
Sie unterscheiden sich jedoch von normalen Entitätstypen durch Folgendes:
- Es kann kein Schlüssel definiert werden.
- Sie werden nie auf Änderungen in der DbContext- hin nachverfolgt und daher niemals in der Datenbank eingefügt, aktualisiert oder gelöscht.
- Sie werden niemals durch Konventionen entdeckt.
- Sie unterstützen nur eine Untergruppe von Navigationsmapping-Funktionen, insbesondere:
- Sie fungieren niemals als übergeordnete Endfunktion einer Beziehung.
- Möglicherweise verfügen sie nicht über Navigationen zu eigenen Entitäten.
- Sie können nur Referenznavigationseigenschaften enthalten, die auf normale Entitäten verweisen.
- Entitäten können keine Navigationseigenschaften für schlüssellose Entitätstypen enthalten.
- Sie müssen mit einer
[Keyless]
-Datenanmerkung oder einem.HasNoKey()
-Methodenaufruf konfiguriert werden. - Sie können einer definierenden Abfrage zugeordnet werden. Eine definierende Abfrage ist eine im Modell deklarierte Abfrage, die als Datenquelle für einen schlüssellosen Entitätstyp fungiert.
- Sie können eine Hierarchie aufweisen, müssen aber als TPH zugeordnet werden.
- Tabellenaufteilung oder Entitätsteilung kann nicht verwendet werden.
Verwendungsszenarios
Einige der wichtigsten Verwendungsszenarien für schlüssellose Entitätstypen sind:
- Sie dienen als Rückgabetyp für SQL-Abfragen.
- Mapping zu Datenbankansichten, die keinen Primärschlüssel enthalten.
- Mapping zu Tabellen, für die kein Primärschlüssel definiert ist.
- Mapping zu im Modell definierten Abfragen.
Mapping zu Datenbankobjekten
Mapping eines schlüssellosen Entitätstyps zu einem Datenbankobjekt wird mithilfe der ToTable
- oder ToView
-Fluent-API erreicht. Aus Sicht von EF Core ist das in dieser Methode angegebene Datenbankobjekt eine Ansicht, was bedeutet, dass es als schreibgeschützte Abfragequelle behandelt wird und nicht das Ziel von Aktualisierungs-, Einfüge- oder Löschvorgängen sein kann. Dies bedeutet jedoch nicht, dass das Datenbankobjekt tatsächlich eine Datenbankansicht sein muss. Alternativ kann es sich um eine Datenbanktabelle handeln, die schreibgeschützt behandelt wird. Umgekehrt geht EF Core bei regulären Entitätstypen davon aus, dass ein in der ToTable
-Methode angegebenes Datenbankobjekt wie eine Tabelle behandelt werden kann, was bedeutet, dass es als Abfragequelle verwendet werden kann, aber auch Ziel von Aktualisierungs-, Lösch- und Einfügevorgängen sein kann. Tatsächlich können Sie den Namen einer Datenbankansicht in ToTable
angeben, und alles sollte einwandfrei funktionieren, solange die Ansicht so konfiguriert ist, dass sie in der Datenbank aktualisierbar ist.
Beispiel
Das folgende Beispiel zeigt, wie schlüssellose Entitätstypen zum Abfragen einer Datenbankansicht verwendet werden.
Tipp
Das in diesem Artikel verwendete Beispiel finden Sie auf GitHub.
Zunächst definieren wir ein einfaches Blog- und Beitragsmodell:
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; }
}
Als Nächstes definieren wir eine einfache Datenbankansicht, mit der wir die Anzahl der mit jedem Blog verbundenen Beiträge abfragen können:
db.Database.ExecuteSqlRaw(
@"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");
Als Nächstes definieren wir eine Klasse, die das Ergebnis aus der Datenbankansicht enthält:
public class BlogPostsCount
{
public string BlogName { get; set; }
public int PostCount { get; set; }
}
Als Nächstes konfigurieren wir den schlüssellosen Entitätstyp in OnModelCreating mithilfe der HasNoKey
-API.
Wir verwenden die Fluent-Konfigurations-API, um die Zuordnung für den schlüssellosen Entitätstyp zu konfigurieren:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder
.Entity<BlogPostsCount>(
eb =>
{
eb.HasNoKey();
eb.ToView("View_BlogPostCounts");
eb.Property(v => v.BlogName).HasColumnName("Name");
});
}
Als Nächstes konfigurieren wir die DbContext
zur Aufnahme der DbSet<T>
:
public DbSet<BlogPostsCount> BlogPostCounts { get; set; }
Schließlich können wir die Datenbankansicht standardmäßig abfragen:
var postCounts = db.BlogPostCounts.ToList();
foreach (var postCount in postCounts)
{
Console.WriteLine($"{postCount.BlogName} has {postCount.PostCount} posts.");
Console.WriteLine();
}
Tipp
Beachten Sie, dass wir auch eine Abfrageeigenschaft auf Kontextebene (DbSet) definiert haben, die als Stamm für Abfragen dieses Typs dient.
Tipp
Um schlüssellose Entitätstypen zu testen, die mithilfe des In-Memory-Anbieters auf Ansichten abgebildet werden, ordnen Sie sie über ToInMemoryQuery einer Abfrage zu. Weitere Informationen finden Sie in der In-Memory-Anbieterdokumentation.