Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
.NET-Standard 2.0
EF Core zielt jetzt auf .NET Standard 2.0 ab, was bedeutet, dass es mit .NET Core 2.0, .NET Framework 4.6.1 und anderen Bibliotheken arbeiten kann, die .NET Standard 2.0 implementieren. Weitere Informationen zu den unterstützten .NET-Implementierungen finden Sie unter "Unterstützte .NET-Implementierungen ".
Modellierung
Tabellenaufteilung
Es ist jetzt möglich, zwei oder mehr Entitätstypen auf dieselbe Tabelle abzubilden, wobei die Primärschlüsselsäulen gemeinsam genutzt werden und jede Zeile zwei oder mehr Entitäten zugeordnet wird.
Um die Aufteilung einer Tabelle mit einer identifizierenden Beziehung zu verwenden (wobei Fremdschlüsseleigenschaften den Primärschlüssel bilden), muss zwischen allen Entitätstypen, die die Tabelle gemeinsam nutzen, eine Konfiguration vorgenommen werden.
modelBuilder.Entity<Product>()
.HasOne(e => e.Details).WithOne(e => e.Product)
.HasForeignKey<ProductDetails>(e => e.Id);
modelBuilder.Entity<Product>().ToTable("Products");
modelBuilder.Entity<ProductDetails>().ToTable("Products");
Weitere Informationen zu diesem Feature finden Sie im Abschnitt zur Tabellenaufteilung .
Besitzertypen
Ein besitzereigener Entitätstyp kann denselben .NET-Typ mit einem anderen Entitätstyp teilen, aber da er nicht nur durch den .NET-Typ identifiziert werden kann, muss eine Navigation von einem anderen Entitätstyp aus vorhanden sein. Die Entität, die die definierende Navigation enthält, ist der Besitzer. Beim Abfragen des Besitzers werden die besessenen Typen standardmäßig eingeschlossen.
Standardmäßig wird ein Schatten-Primärschlüssel für den eigenen Typ erstellt, und er wird der gleichen Tabelle zugeordnet wie der Besitzer mithilfe der Tabellenaufteilung. Dies ermöglicht die Verwendung von eigenen Typen in ähnlicher Weise wie komplexe Typen in EF6:
modelBuilder.Entity<Order>().OwnsOne(p => p.OrderDetails, cb =>
{
cb.OwnsOne(c => c.BillingAddress);
cb.OwnsOne(c => c.ShippingAddress);
});
public class Order
{
public int Id { get; set; }
public OrderDetails OrderDetails { get; set; }
}
public class OrderDetails
{
public StreetAddress BillingAddress { get; set; }
public StreetAddress ShippingAddress { get; set; }
}
public class StreetAddress
{
public string Street { get; set; }
public string City { get; set; }
}
Weitere Informationen zu dieser Funktion finden Sie im Abschnitt zu eigenen Entitätstypen.
Abfragefilter auf Modellebene
EF Core 2.0 enthält eine neue Funktion, die wir Abfragefilter auf Modellebene nennen. Mit diesem Feature können LINQ-Abfrageprädikate (ein boolescher Ausdruck, der in der Regel an den LINQ Where-Abfrageoperator übergeben wird) direkt für Entitätstypen im Metadatenmodell definiert werden (normalerweise in OnModelCreating). Solche Filter werden automatisch auf ALLE LINQ-Abfragen angewendet, die diese Entitätstypen umfassen, einschließlich Entitätstypen, auf die indirekt verwiesen wird, z. B. durch die Verwendung von Include- oder direkten Navigationseigenschaftenverweise. Einige gängige Anwendungen dieses Features sind:
- Vorläufiges Löschen – Ein Entitätstyp definiert eine IsDeleted-Eigenschaft.
- Mehrinstanzenmandant – Ein Entitätstyp definiert eine TenantId-Eigenschaft.
Hier ist ein einfaches Beispiel, das das Feature für die beiden oben aufgeführten Szenarien veranschaulicht:
public class BloggingContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
public DbSet<Post> Posts { get; set; }
public int TenantId { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Post>().HasQueryFilter(
p => !p.IsDeleted
&& p.TenantId == this.TenantId);
}
}
Wir definieren einen Filter auf Modellebene, der mehrinstanzenfähige und vorläufiges Löschen für Instanzen des Post Entitätstyps implementiert. Beachten Sie die Verwendung einer DbContext Eigenschaft auf Instanzebene: TenantId. Filter auf Modellebene verwenden den Wert aus der richtigen Kontextinstanz (d. a. die Kontextinstanz, die die Abfrage ausführt).
Filter können für einzelne LINQ-Abfragen mit dem Operator IgnoreQueryFilters() deaktiviert werden.
Einschränkungen
- Navigationsverweise sind nicht zulässig. Dieses Feature kann basierend auf Feedback hinzugefügt werden.
- Filter können nur für den Stammentitätstyp einer Hierarchie definiert werden.
Zuordnung der skalaren Datenbankfunktionen
EF Core 2.0 enthält einen wichtigen Beitrag von Paul Middleton , der das Zuordnen von skalaren Datenbankfunktionen zu Methoden-Stubs ermöglicht, damit sie in LINQ-Abfragen verwendet und in SQL übersetzt werden können.
Hier ist eine kurze Beschreibung, wie das Feature verwendet werden kann:
Deklarieren Sie eine statische Methode für Ihre DbContext Methode, und kommentieren Sie sie mit DbFunctionAttribute:
public class BloggingContext : DbContext
{
[DbFunction]
public static int PostReadCount(int blogId)
{
throw new NotImplementedException();
}
}
Methoden wie diese werden automatisch registriert. Nach der Registrierung können Aufrufe der Methode in einer LINQ-Abfrage in Funktionsaufrufe in SQL übersetzt werden:
var query =
from p in context.Posts
where BloggingContext.PostReadCount(p.Id) > 5
select p;
Einige wichtige Punkte:
- In der Konvention wird der Name der Methode als Name einer Funktion (in diesem Fall eine benutzerdefinierte Funktion) beim Generieren von SQL verwendet, aber Sie können den Namen und das Schema während der Methodenregistrierung außer Kraft setzen.
- Derzeit werden nur skalare Funktionen unterstützt.
- Sie müssen die zugeordnete Funktion in der Datenbank erstellen. EF Core-Migrationen kümmern sich nicht um die Erstellung.
Eigenständige Typkonfiguration für Code-First
In EF6 war es möglich, die erste Konfiguration des Codes eines bestimmten Entitätstyps durch Ableiten von EntityTypeConfiguration zu kapseln. In EF Core 2.0 bringen wir dieses Muster zurück:
class CustomerConfiguration : IEntityTypeConfiguration<Customer>
{
public void Configure(EntityTypeBuilder<Customer> builder)
{
builder.HasKey(c => c.AlternateKey);
builder.Property(c => c.Name).HasMaxLength(200);
}
}
...
// OnModelCreating
builder.ApplyConfiguration(new CustomerConfiguration());
Leistung
DbContext-Pooling
Das grundlegende Muster für die Verwendung von EF Core in einer ASP.NET Core-Anwendung umfasst in der Regel das Registrieren eines benutzerdefinierten DbContext-Typs im Abhängigkeitseinfügungssystem und das spätere Abrufen von Instanzen dieses Typs über Konstruktorparameter in Controllern. Dies bedeutet, dass für jede Anforderung eine neue Instanz des DbContext-Elements erstellt wird.
In Version 2.0 wird eine neue Methode zum Registrieren von benutzerdefinierten DbContext-Typen in Abhängigkeitsinjektion eingeführt, wodurch transparent ein Pool wiederverwendbarer DbContext-Instanzen eingeführt wird. Um DbContext-Pooling zu verwenden, nutzen Sie AddDbContextPool anstelle von AddDbContext während der Dienstregistrierung.
services.AddDbContextPool<BloggingContext>(
options => options.UseSqlServer(connectionString));
Wenn diese Methode verwendet wird, wird zum Zeitpunkt, zu dem eine DbContext-Instanz von einem Controller angefordert wird, zuerst überprüft, ob eine Instanz im Pool verfügbar ist. Sobald die Anforderungsverarbeitung abgeschlossen ist, wird jeder Zustand der Instanz zurückgesetzt, und die Instanz wird selbst an den Pool zurückgegeben.
Dies ähnelt konzeptuell der Funktionsweise von Verbindungspooling in ADO.NET Anbietern und hat den Vorteil, einige der Kosten für die Initialisierung der DbContext-Instanz zu sparen.
Einschränkungen
Die neue Methode führt einige Einschränkungen für die Aktionen in der OnConfiguring() Methode von DbContext ein.
Warnung
Vermeiden Sie die Verwendung von DbContext-Poolen, wenn Sie Ihren eigenen Zustand (z. B. private Felder) in Ihrer abgeleiteten DbContext-Klasse verwalten, der nicht über Anforderungen hinweg freigegeben werden sollte. EF Core setzt nur den Status zurück, den er vor dem Hinzufügen einer DbContext-Instanz zum Pool kennt.
Explizit kompilierte Abfragen
Dies ist das zweite leistungsfähige Opt-In-Feature, das Vorteile in Szenarien mit hoher Skalierbarkeit bietet.
Manuelle oder explizit kompilierte Abfrage-APIs sind in früheren Versionen von EF und auch in LINQ to SQL verfügbar, damit Anwendungen die Übersetzung von Abfragen zwischenspeichern können, damit sie nur einmal berechnet und mehrmals ausgeführt werden können.
Obwohl EF Core im Allgemeinen Abfragen basierend auf einer Hashdarstellung der Abfrageausdrücke automatisch kompilieren und zwischenspeichern kann, kann dieser Mechanismus verwendet werden, um einen kleinen Leistungsgewinn zu erhalten, indem die Berechnung des Hashs und der Cachesuche umgangen wird, sodass die Anwendung eine bereits kompilierte Abfrage über den Aufruf eines Delegaten verwenden kann.
// Create an explicitly compiled query
private static Func<CustomerContext, int, Customer> _customerById =
EF.CompileQuery((CustomerContext db, int id) =>
db.Customers
.Include(c => c.Address)
.Single(c => c.Id == id));
// Use the compiled query by invoking it
using (var db = new CustomerContext())
{
var customer = _customerById(db, 147);
}
Änderungsnachverfolgung
Attach kann ein Diagramm mit neuen und vorhandenen Entitäten verfolgen.
EF Core unterstützt die automatische Generierung von Schlüsselwerten über eine Vielzahl von Mechanismen. Bei Verwendung dieses Features wird ein Wert generiert, wenn es sich bei der Schlüsseleigenschaft um die CLR-Standardeigenschaft (in der Regel Null oder Null) handelt. Dies bedeutet, dass ein Diagramm von Entitäten an DbContext.Attach oder EF Core übergeben werden kann, DbSet.Attach und EF Core markiert diese Entitäten, die bereits einen Schlüssel festgelegt haben, Unchanged während diese Entitäten, die keinen Schlüsselsatz besitzen, als Addedgekennzeichnet werden. Dies erleichtert das Anfügen eines Diagramms gemischter neuer und vorhandener Entitäten bei Verwendung generierter Schlüssel.
DbContext.Update und DbSet.Update funktionieren auf die gleiche Weise, abgesehen davon, dass Entitäten mit einem Schlüsselsatz als Modified anstelle von Unchanged markiert werden.
Abfrage
Verbesserte LINQ-Übersetzung
Ermöglicht eine erfolgreiche Ausführung von Abfragen, wobei mehr Logik in der Datenbank ausgewertet wird (und nicht im Arbeitsspeicher), und weniger Daten unnötigerweise aus der Datenbank abgerufen werden.
Verbesserungen bei GroupJoin
Diese Arbeit verbessert die SQL-Datei, die für Gruppenbeitritte generiert wird. Gruppenverknüpfungen sind am häufigsten ein Ergebnis von Unterabfragen mit optionalen Navigationseigenschaften.
Zeichenfolgeninterpolation in FromSql und ExecuteSqlCommand
C# 6 hat die Zeichenfolgeninterpolation eingeführt, ein Feature, mit dem C#-Ausdrücke direkt in Zeichenfolgenliterale eingebettet werden können, wodurch eine gute Möglichkeit zum Erstellen von Zeichenfolgen zur Laufzeit bereitgestellt wird. In EF Core 2.0 wurden spezielle Unterstützung für interpolierte Zeichenfolgen zu unseren beiden primären APIs hinzugefügt, die unformatierte SQL-Zeichenfolgen akzeptieren: FromSql und ExecuteSqlCommand. Diese neue Unterstützung ermöglicht die Verwendung der C#-Zeichenfolgeninterpolation auf sichere Weise. Das heißt, auf eine Weise, die vor allgemeinen SQL-Einfügefehlern schützt, die beim dynamischen Erstellen von SQL während der Laufzeit auftreten können.
Hier ist ein Beispiel:
var city = "London";
var contactTitle = "Sales Representative";
using (var context = CreateContext())
{
context.Set<Customer>()
.FromSql($@"
SELECT *
FROM ""Customers""
WHERE ""City"" = {city} AND
""ContactTitle"" = {contactTitle}")
.ToArray();
}
In diesem Beispiel sind zwei Variablen in die SQL-Formatzeichenfolge eingebettet. EF Core erzeugt folgendes SQL:
@p0='London' (Size = 4000)
@p1='Sales Representative' (Size = 4000)
SELECT *
FROM ""Customers""
WHERE ""City"" = @p0
AND ""ContactTitle"" = @p1
EF.Functions.Like()
Wir haben die EF.Functions-Eigenschaft hinzugefügt, die von EF Core oder Providern genutzt werden kann, um Methoden zu definieren, die Datenbankfunktionen oder Operatoren zugeordnet werden, sodass diese in LINQ-Abfragen aufgerufen werden können. Das erste Beispiel für eine solche Methode ist Like():
var aCustomers =
from c in context.Customers
where EF.Functions.Like(c.Name, "a%")
select c;
Beachten Sie, dass Like() eine speicherinterne Implementierung bietet, die bei der Arbeit mit einer speicherinternen Datenbank oder wenn die Auswertung des Prädikats auf der Client-Seite erfolgen muss, nützlich sein kann.
Datenbankverwaltung
Pluralisierungs-Hook für DbContext-Gerüst
EF Core 2.0 führt einen neuen IPluralizer-Dienst ein, der zum Singularisieren von Entitätstypnamen und Pluralisierung von DbSet-Namen verwendet wird. Die Standardimplementierung ist ein no-op, daher ist dies nur ein Hook, bei dem Die Leute einfach ihren eigenen Pluralisierer anschließen können.
So sieht es aus, wie ein Entwickler einen eigenen Pluralisierer integriert:
public class MyDesignTimeServices : IDesignTimeServices
{
public void ConfigureDesignTimeServices(IServiceCollection services)
{
services.AddSingleton<IPluralizer, MyPluralizer>();
}
}
public class MyPluralizer : IPluralizer
{
public string Pluralize(string name)
{
return Inflector.Inflector.Pluralize(name) ?? name;
}
public string Singularize(string name)
{
return Inflector.Inflector.Singularize(name) ?? name;
}
}
Andere
Verschieben Sie den ADO.NET SQLite-Anbieter nach SQLitePCL.raw
Dadurch erhalten wir eine robustere Lösung in Microsoft.Data.Sqlite zum Verteilen nativer SQLite-Binärdateien auf verschiedenen Plattformen.
Nur ein Anbieter pro Modell
Erweitert die Interaktion von Anbietern mit dem Modell erheblich und vereinfacht die Funktionsweise von Konventionen, Anmerkungen und Fluent-APIs mit verschiedenen Anbietern.
EF Core 2.0 erstellt nun ein anderes IModel für jeden verschiedenen Anbieter, der verwendet wird. Dies ist in der Regel transparent für die Anwendung. Dies hat eine Vereinfachung von Metadaten-APIs auf niedrigerer Ebene erleichtert, sodass jeder Zugriff auf allgemeine relationale Metadatenkonzepte immer über einen Aufruf .Relational anstelle von .SqlServer, .Sqliteusw. erfolgt.
Konsolidierte Protokollierung und Diagnose
Die Protokollierungsmechanismen (basierend auf ILogger) und Diagnosemechanismen (basierend auf DiagnosticSource) teilen jetzt mehr Code.
Die Ereignis-IDs für An einen ILogger gesendete Nachrichten wurden in 2.0 geändert. Die Ereignis-IDs sind jetzt über EF Core-Code hinweg eindeutig. Diese Nachrichten folgen nun auch dem Standardmuster für strukturiertes Logging, das z. B. von MVC verwendet wird.
Die Kategorien der Logger wurden ebenfalls geändert. Es gibt jetzt eine bekannte Gruppe von Kategorien, auf die über DbLoggerCategory zugegriffen wird.
DiagnosticSource-Ereignisse verwenden jetzt dieselben Ereignis-ID-Namen wie die entsprechenden ILogger Nachrichten.