Abfragen mit Nachverfolgung im Vergleich zu Abfragen ohne NachverfolgungTracking vs. No-Tracking Queries

Das Nachverfolgungsverhalten steuert, ob Entity Framework Core Informationen über eine Entitätsinstanz in der Änderungsprotokollierung speichert.Tracking behavior controls if Entity Framework Core will keep information about an entity instance in its change tracker. Wenn eine Entität nachverfolgt wird, werden alle Änderungen, die in der Entität erkannt werden, während SaveChanges() in der Datenbank beibehalten.If an entity is tracked, any changes detected in the entity will be persisted to the database during SaveChanges(). EF Core korrigiert auch Unstimmigkeiten zwischen den Navigationseigenschaften von Entitäten in einem Nachverfolgungs-Abfrageergebnis und Entitäten, die sich in der Änderungsprotokollierung befinden.EF Core will also fix up navigation properties between the entities in a tracking query result and the entities that are in the change tracker.

Hinweis

Schlüssellose Entitätstypen werden nie nachverfolgt.Keyless entity types are never tracked. Wenn in diesem Artikel Entitätstypen erwähnt werden, sind Entitätstypen gemeint, für die ein Schlüssel definiert ist.Wherever this article mentions entity types, it refers to entity types which have a key defined.

Tipp

Das in diesem Artikel verwendete Beispiel finden Sie auf GitHub.You can view this article's sample on GitHub.

Abfragen mit NachverfolgungTracking queries

Abfragen, die Entitätstypen zurückgeben, verfügen standardmäßig über Nachverfolgung.By default, queries that return entity types are tracking. Das bedeutet, Sie können Änderungen an diesen Entitätsinstanzen vornehmen, und diese Änderungen werden von SaveChanges() beibehalten.Which means you can make changes to those entity instances and have those changes persisted by SaveChanges(). Im folgenden Beispiel wird die Änderung an der Bewertung des Blogs erkannt und während SaveChanges() in der Datenbank beibehalten.In the following example, the change to the blogs rating will be detected and persisted to the database during SaveChanges().

var blog = context.Blogs.SingleOrDefault(b => b.BlogId == 1);
blog.Rating = 5;
context.SaveChanges();

Wenn die Ergebnisse in einer Abfrage mit Nachverfolgung zurückgegeben werden, prüft EF Core, ob die Entität bereits im Kontext ist.When the results are returned in a tracking query, EF Core will check if the entity is already in the context. Wenn EF Core eine vorhandene Entität findet, wird dieselbe Instanz zurückgegeben.If EF Core finds an existing entity, then the same instance is returned. EF Core überschreibt im Eintrag mit den Datenbankwerten nicht die aktuellen und ursprünglichen Werte der Eigenschaften der Entität.EF Core won't overwrite current and original values of the entity's properties in the entry with the database values. Wenn die Entität nicht im Kontext gefunden wird, erstellt EF Core eine neue Entitätsinstanz und fügt sie an den Kontext an.If the entity isn't found in the context, then EF Core will create new entity instance and attach it to the context. Abfrageergebnisse enthalten keine Entität, die dem Kontext hinzugefügt, aber noch nicht in der Datenbank gespeichert wurde.Query results don't contain any entity, which is added to the context but not yet saved to the database.

Abfragen ohne NachverfolgungNo-tracking queries

Abfragen ohne Nachverfolgung sind nützlich, wenn die Ergebnisse in einem schreibgeschützten Szenario verwendet werden.No tracking queries are useful when the results are used in a read-only scenario. Sie werden schneller ausgeführt, da keine Informationen für die Änderungsnachverfolgung eingerichtet werden müssen.They're quicker to execute because there's no need to set up the change tracking information. Wenn Sie die aus der Datenbank abgerufenen Entitäten nicht aktualisieren müssen, sollte eine Abfrage ohne Nachverfolgung verwendet werden.If you don't need to update the entities retrieved from the database, then a no-tracking query should be used. Sie können eine einzelne Abfrage ändern, sodass sie keine Nachverfolgung ausführt.You can swap an individual query to be no-tracking. Keine Abfrage mit Nachverfolgung liefert Ihnen zudem Ergebnisse, die auf dem Inhalt der Datenbank basieren, wobei lokale Änderungen oder hinzugefügte Entitäten unberücksichtigt bleiben.No tracking query will also give you results based on what is in the database disregarding any local changes or added entities.

var blogs = context.Blogs
    .AsNoTracking()
    .ToList();

Sie können das Standardnachverfolgungsverhalten auch auf der Ebene der Kontextinstanz ändern:You can also change the default tracking behavior at the context instance level:

context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;

var blogs = context.Blogs.ToList();

IdentitätsauflösungIdentity resolution

Da eine Nachverfolgungsabfrage die Änderungsprotokollierung verwendet, führt EF Core in einer Nachverfolgungsabfrage eine Identitätsauflösung durch.Since a tracking query uses the change tracker, EF Core will do identity resolution in a tracking query. Beim Materialisieren einer Entität gibt EF Core dieselbe Entitätsinstanz aus der Änderungsprotokollierung zurück, wenn sie bereits nachverfolgt wird.When materializing an entity, EF Core will return the same entity instance from the change tracker if it's already being tracked. Wenn das Ergebnis mehrmals dieselbe Entität enthält, erhalten Sie für jedes Vorkommen dieselbe Instanz.If the result contains same entity multiple times, you get back same instance for each occurrence. Abfragen ohne Nachverfolgung verwenden weder die Änderungsprotokollierung, noch führen sie eine Identitätsauflösung durch.No-tracking queries don't use the change tracker and don't do identity resolution. Sie erhalten also auch dann eine neue Instanz der Entität, wenn dieselbe Entität mehrmals im Ergebnis enthalten ist.So you get back new instance of entity even when the same entity is contained in the result multiple times. Dieses Verhalten war in Versionen vor EF Core 3.0 anders, siehe frühere Versionen.This behavior was different in versions before EF Core 3.0, see previous versions.

Ab EF Core 5.0 können Sie beide oben genannten Verhalten in derselben Abfrage kombinieren.Starting with EF Core 5.0, you can combine both of the above behaviors in same query. Das heißt, Sie können eine Abfrage ohne Nachverfolgung haben, die eine Identitätsauflösung in den Ergebnissen vornimmt.That is, you can have a no tracking query, which will do identity resolution in the results. Genau wie den abfragbaren Operator AsNoTracking() haben wir mit AsNoTrackingWithIdentityResolution() einen weiteren Operator hinzugefügt.Just like AsNoTracking() queryable operator, we've added another operator AsNoTrackingWithIdentityResolution(). Der Enumeration QueryTrackingBehavior wurde außerdem ein zugeordneter Eintrag hinzugefügt.There's also associated entry added in QueryTrackingBehavior enum. Wenn Sie die Abfrage so konfigurieren, dass die Identitätsauflösung ohne Nachverfolgung verwendet wird, verwenden wir bei der Generierung der Abfrageergebnisse eine eigenständige Änderungsnachverfolgung im Hintergrund, sodass jede Instanz sich nur einmal materialisiert.When you configure the query to use identity resolution with no tracking, we use a stand-alone change tracker in the background when generating query results so each instance is materialized only once. Da sich diese Änderungsnachverfolgung von der im Kontext unterscheidet, werden die Ergebnisse nicht vom Kontext nachverfolgt.Since this change tracker is different from the one in the context, the results are not tracked by the context. Nachdem die Abfrage vollständig aufgezählt ist, verlässt die Änderungsnachverfolgung den Gültigkeitsbereich, und die Garbage Collection erfolgt den Anforderungen entsprechend.After the query is enumerated fully, the change tracker goes out of scope and garbage collected as required.

var blogs = context.Blogs
    .AsNoTrackingWithIdentityResolution()
    .ToList();

Nachverfolgung und benutzerdefinierte ProjektionenTracking and custom projections

Selbst wenn der Ergebnistyp der Abfrage kein Entitätstyp ist, verfolgt EF Core im Ergebnis enthaltene Entitätstypen standardmäßig nach.Even if the result type of the query isn't an entity type, EF Core will still track entity types contained in the result by default. In der folgenden Abfrage, die einen anonymen Typ zurückgibt, werden die Instanzen von Blog im Ergebnis nachverfolgt.In the following query, which returns an anonymous type, the instances of Blog in the result set will be tracked.

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, werden sie von EF Core nachverfolgt.If the result set contains entity types coming out from LINQ composition, EF Core will track them.

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 ausgeführt.If the result set doesn't contain any entity types, then no tracking is done. In der folgenden Abfrage geben wir einen anonymen Typ mit einigen Werten der Entität zurück (aber keine Instanzen des aktuellen Entitätstyps).In the following query, we return an anonymous type with some of the values from the entity (but no instances of the actual entity type). Es sind keine aus der Abfrage stammenden nachverfolgten Entitäten vorhanden.There are no tracked entities coming out of the query.

var blog = context.Blogs
    .Select(b =>
        new
        {
            Id = b.BlogId,
            Url = b.Url
        });

EF Core unterstützt die Clientauswertung in der Projektion auf oberster Ebene.EF Core supports doing client evaluation in the top-level projection. Wenn EF Core eine Entitätsinstanz für die Clientauswertung materialisiert, wird sie nachverfolgt.If EF Core materializes an entity instance for client evaluation, it will be tracked. Da wir hier blog-Entitäten an die Clientmethode StandardizeURL übergeben, verfolgt EF Core auch die Bloginstanzen nach.Here, since we're passing blog entities to the client method StandardizeURL, EF Core will track the blog instances too.

var blogs = context.Blogs
    .OrderByDescending(blog => blog.Rating)
    .Select(blog => new
    {
        Id = blog.BlogId,
        Url = StandardizeUrl(blog)
    })
    .ToList();
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 nach, die im Ergebnis enthalten sind.EF Core doesn't track the keyless entity instances contained in the result. EF Core verfolgt jedoch alle anderen Instanzen von Entitätstypen mit Schlüssel gemäß den oben aufgeführten Regeln nach.But EF Core tracks all the other instances of entity types with key according to rules above.

Einige der oben genannten Regeln funktionierten vor EF Core 3.0 anders.Some of the above rules worked differently before EF Core 3.0. Weitere Informationen siehe frühere Versionen.For more information, see previous versions.

Vorherige VersionenPrevious versions

Vor Version 3.0 wies EF Core bei der Nachverfolgung einige Unterschiede auf.Before version 3.0, EF Core had some differences in how tracking was done. Wesentliche Unterschiede sind:Notable differences are as follows:

  • Wie auf der Seite Clientauswertung im Vergleich zur Serverauswertung erläutert, unterstützte EF Core vor Version 3.0 die Clientauswertung in einem beliebigen Teil der Abfrage.As explained in Client vs Server Evaluation page, EF Core supported client evaluation in any part of the query before version 3.0. Die Clientauswertung verursachte Materialisierungen von Entitäten, die nicht Teil des Ergebnisses waren.Client evaluation caused materialization of entities, which weren't part of the result. Daher analysierte EF Core das Ergebnis, um zu ermitteln, was nachverfolgt werden soll. Dieser Entwurf wies wie folgt bestimmte Unterschiede auf:So EF Core analyzed the result to detect what to track. This design had certain differences as follows:

    • Clientauswertung in der Projektion, die die Materialisierung verursachte, aber die materialisierte Entitätsinstanz nicht zurückgab, wurde nicht nachverfolgt.Client evaluation in the projection, which caused materialization but didn't return the materialized entity instance wasn't tracked. Im folgenden Beispiel wurden blog-Entitäten nicht nachverfolgt.The following example didn't track blog entities.

      var blogs = context.Blogs
          .OrderByDescending(blog => blog.Rating)
          .Select(blog => new
          {
              Id = blog.BlogId,
              Url = StandardizeUrl(blog)
          })
          .ToList();
      
    • In bestimmten Fällen wurden aus der LINQ-Komposition stammende Objekte von EF Core nicht nachverfolgt.EF Core didn't track the objects coming out of LINQ composition in certain cases. Im folgenden Beispiel wurde Post nicht nachverfolgt.The following example didn't track Post.

      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.Whenever query results contained keyless entity types, the whole query was made non-tracking. Dies bedeutet, dass Entitätstypen mit Schlüsseln, die sich in einem Ergebnis befanden, auch nicht nachverfolgt wurden.That means that entity types with keys, which are in result weren't being tracked either.

  • EF Core führte in Abfragen ohne Nachverfolgung keine Identitätsauflösung durch.EF Core did identity resolution in no-tracking query. Schwache Verweise wurden verwendet, um bereits zurückgegebene Entitäten nachzuverfolgen.It used weak references to keep track of entities that had already been returned. Wenn also ein Resultset dieselbe Entität mehrfach enthielt, erhielten Sie für jedes Vorkommen dieselbe Instanz.So if a result set contained the same entity multiples times, you would get the same instance for each occurrence. Auch wenn ein vorheriges Ergebnis mit derselben Identität den Gültigkeitsbereich verließ und eine Garbage Collection durchgeführt wurde, gab EF Core eine neue Instanz zurück.Though if a previous result with the same identity went out of scope and got garbage collected, EF Core returned a new instance.