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.
Die Überwachung des Verhaltens bestimmt, ob Entity Framework Core Informationen über eine Entitätsinstanz in seinem Änderungsprotokoll speichert. Wenn eine Entität nachverfolgt wird, werden alle erkannten Änderungen der Entität während SaveChanges
in der Datenbank gespeichert. EF Core behebt auch Navigationseigenschaften zwischen den Entitäten in einem Nachverfolgungsabfrageergebnis und den Entitäten, die sich in der Änderungsverfolgung befinden.
Hinweis
Schlüssellose Entitätstypen werden nie nachverfolgt. Unabhängig davon, wo in diesem Artikel Entitätstypen erwähnt werden, bezieht er sich auf Entitätstypen, die einen Schlüssel definiert haben.
Tipp
Das in diesem Artikel verwendete Beispiel finden Sie auf GitHub.
Nachverfolgen von Abfragen
Standardmäßig werden Abfragen, die Entitätstypen zurückgeben, nachverfolgt. Eine Nachverfolgungsabfrage bedeutet, dass alle Änderungen an Entitätsinstanzen beibehalten werden SaveChanges
. Im folgenden Beispiel wird die Änderung der Blog-Bewertung erkannt und während SaveChanges
in der Datenbank persistiert.
var blog = await context.Blogs.SingleOrDefaultAsync(b => b.BlogId == 1);
blog.Rating = 5;
await context.SaveChangesAsync();
Wenn die Ergebnisse in einer Nachverfolgungsabfrage zurückgegeben werden, überprüft EF Core, ob sich die Entität bereits im Kontext befindet. Wenn EF Core eine vorhandene Entität findet, wird dieselbe Instanz zurückgegeben, die potenziell weniger Arbeitsspeicher und schneller als eine No-Tracking-Abfrage verwenden kann. EF Core überschreibt keine aktuellen und ursprünglichen Werte der Eigenschaften der Entität im Eintrag mit den Datenbankwerten. Wenn die Entität im Kontext nicht gefunden wird, erstellt EF Core eine neue Entitätsinstanz und fügt sie dem Kontext an. Abfrageergebnisse enthalten keine Entität, die dem Kontext hinzugefügt, aber noch nicht in der Datenbank gespeichert wurde.
Keine Nachverfolgungsabfragen
No-Tracking-Abfragen sind nützlich, wenn die Ergebnisse in einem schreibgeschützten Szenario verwendet werden. Sie sind im Allgemeinen schneller auszuführen, da die Änderungsnachverfolgungsinformationen nicht eingerichtet werden müssen. Wenn die aus der Datenbank abgerufenen Entitäten nicht aktualisiert werden müssen, sollte eine No-Tracking-Abfrage verwendet werden. Eine einzelne Abfrage kann so eingerichtet werden, dass sie nicht nachverfolgt wird. Eine No-Tracking-Abfrage gibt auch Ergebnisse basierend auf dem, was sich in der Datenbank befindet, ohne lokale Änderungen oder hinzugefügte Entitäten zu ignorieren.
var blogs = await context.Blogs
.AsNoTracking()
.ToListAsync();
Das Standardnachverfolgungsverhalten kann auf Kontextinstanzebene geändert werden:
context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
var blogs = await context.Blogs.ToListAsync();
Im nächsten Abschnitt wird erläutert, wann eine No-Tracking-Abfrage möglicherweise weniger effizient ist als eine Nachverfolgungsabfrage.
Identitätsauflösung
Da eine Verfolgungsabfrage den Änderungsverfolger verwendet, führt EF Core die Identitätsauflösung in einer solchen Abfrage durch. Bei der Materialisierung einer Entität gibt EF Core die gleiche Entitätsinstanz aus der Änderungsverfolgung zurück, wenn sie bereits nachverfolgt wird. Wenn das Ergebnis mehrmals dieselbe Entität enthält, wird für jedes Vorkommen dieselbe Instanz zurückgegeben. Keine Nachverfolgungsabfragen:
- Verwenden Sie die Änderungsverfolgung nicht, und führen Sie keine Identitätsauflösung durch.
- Gibt eine neue Instanz der Entität zurück, auch wenn dieselbe Entität mehrmals im Ergebnis enthalten ist.
Tracking und no-tracking können in derselben Abfrage kombiniert werden. Das heißt, Sie können eine Abfrage ohne Tracking durchführen, die die Identitätsauflösung in den Ergebnissen vornimmt. Genau wie AsNoTracking der abfragefähige Operator haben wir einen anderen Operator AsNoTrackingWithIdentityResolution<TEntity>(IQueryable<TEntity>)hinzugefügt. Zu dem QueryTrackingBehavior Aufzählungstyp wurde auch der zugehörige Eintrag hinzugefügt. Wenn die Abfrage zur Verwendung der Identitätsauflösung ohne Nachverfolgung konfiguriert ist, wird im Hintergrund ein eigenständiger Änderungsverfolger verwendet, um die Abfrageergebnisse zu generieren, sodass jede Instanz nur einmal instanziiert wird. Da sich diese Änderungsverfolgung von der im Kontext unterscheidet, werden die Ergebnisse nicht durch den Kontext nachverfolgt. Nachdem die Abfrage vollständig aufgezählt wurde, verliert der Änderungstracker den Umfang und wird bei Bedarf durch Speicherbereinigung gesammelt.
var blogs = await context.Blogs
.AsNoTrackingWithIdentityResolution()
.ToListAsync();
Konfigurieren des Standardnachverfolgungsverhaltens
Wenn Sie feststellen, dass Sie das Nachverfolgungsverhalten für viele Abfragen ändern, sollten Sie stattdessen die Standardeinstellung ändern:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder
.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFQuerying.Tracking;Trusted_Connection=True;ConnectRetryCount=0")
.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking);
}
Dadurch werden alle Ihre Abfragen standardmäßig nicht nachverfolgt. Sie können weiterhin hinzufügen AsTracking , um bestimmte Abfragen nachzuverfolgen.
Verfolgung und benutzerdefinierte Projektionen
Selbst wenn der Ergebnistyp der Abfrage kein Entitätstyp ist, verfolgt EF Core weiterhin Entitätstypen, die standardmäßig im Ergebnis enthalten sind. In der folgenden Abfrage, die einen anonymen Typ zurückgibt, werden die Instanzen von Blog
im Resultset verfolgt.
var blog = context.Blogs
.Select(
b =>
new { Blog = b, PostCount = b.Posts.Count() });
Wenn das Resultset Entitätstypen enthält, die aus der LINQ-Komposition stammen, verfolgt EF Core sie.
var blog = context.Blogs
.Select(
b =>
new { Blog = b, Post = b.Posts.OrderBy(p => p.Rating).LastOrDefault() });
Wenn das Resultset keine Entitätstypen enthält, wird keine Nachverfolgung durchgeführt. In der folgenden Abfrage geben wir einen anonymen Typ mit einigen der Werte aus der Entität zurück (jedoch keine Instanzen des tatsächlichen Entitätstyps). Es gibt keine nachverfolgten Entitäten, die aus der Abfrage hervorgehen.
var blog = context.Blogs
.Select(
b =>
new { Id = b.BlogId, b.Url });
EF Core unterstützt die Clientauswertung in der obersten Projektionsebene. Wenn EF Core eine Entitätsinstanz für die Clientauswertung materialisiert, wird sie nachverfolgt. Da wir blog
Entitäten an die Clientmethode StandardizeURL
übergeben, wird EF Core auch die Bloginstanzen nachverfolgen.
var blogs = await context.Blogs
.OrderByDescending(blog => blog.Rating)
.Select(
blog => new { Id = blog.BlogId, Url = StandardizeUrl(blog) })
.ToListAsync();
public static string StandardizeUrl(Blog blog)
{
var url = blog.Url.ToLower();
if (!url.StartsWith("http://"))
{
url = string.Concat("http://", url);
}
return url;
}
EF Core verfolgt nicht die schlüssellosen Entitätsinstanzen, die im Ergebnis enthalten sind. EF Core verfolgt jedoch alle anderen Instanzen von Entitätstypen mit einem Schlüssel gemäß den oben genannten Regeln.
Vorherige Versionen
Vor Version 3.0 hatte EF Core einige Unterschiede bei der Nachverfolgung. Wichtige Unterschiede sind wie folgt:
Wie auf der Seite "Client- und Serverauswertung " erläutert, unterstützte EF Core die Clientauswertung in jedem Teil der Abfrage vor Version 3.0. Die Clientauswertung verursachte die Materialisierung von Entitäten, die nicht Teil des Ergebnisses waren. Daher analysierte EF Core das Ergebnis, um zu erkennen, was nachverfolgt werden soll. Dieser Entwurf hatte bestimmte Unterschiede wie folgt:
Die Clientauswertung in der Projektion, die die Materialisierung verursachte, aber die materialisierte Entitätsinstanz nicht zurückgegeben hat, wurde nicht nachverfolgt. Im folgenden Beispiel wurden keine Entitäten nachverfolgt
blog
.var blogs = await context.Blogs .OrderByDescending(blog => blog.Rating) .Select( blog => new { Id = blog.BlogId, Url = StandardizeUrl(blog) }) .ToListAsync();
EF Core hat die Objekte, die aus der LINQ-Komposition stammen, in bestimmten Fällen nicht nachverfolgt. Im folgenden Beispiel konnte
Post
nicht nachverfolgt werden.var blog = context.Blogs .Select( b => new { Blog = b, Post = b.Posts.OrderBy(p => p.Rating).LastOrDefault() });
Wenn Abfrageergebnisse schlüssellose Entitätstypen enthielten, wurde die gesamte Abfrage nicht nachverfolgt. Das bedeutet, dass Entitätstypen mit Schlüsseln, die sich im Ergebnis befinden, auch nicht nachverfolgt wurden.
EF Core führte früher die Identitätsauflösung in No-Tracking-Abfragen durch. Es verwendete schwache Verweise, um Entitäten nachzuverfolgen, die bereits zurückgegeben wurden. Wenn ein Resultset also mehrmals dieselbe Entität enthielt, würden Sie dieselbe Instanz für jedes Vorkommen erhalten. Wenn jedoch ein vorheriges Ergebnis mit derselben Identität außerhalb des Gültigkeitsbereichs lag und vom Garbage Collector entfernt wurde, gab EF Core eine neue Instanz zurück.