Zugreifen auf verfolgte EntitätenAccessing Tracked Entities

Es gibt vier Haupt-APIs für den Zugriff auf Entitäten, die von verfolgt werden DbContext :There are four main APIs for accessing entities tracked by a DbContext:

Diese werden in den folgenden Abschnitten ausführlicher beschrieben.Each of these is described in more detail in the sections below.

Tipp

In diesem Dokument wird davon ausgegangen, dass die Entitäts Zustände und die Grundlagen EF Core Änderungs Nachverfolgung verstanden werden.This document assumes that entity states and the basics of EF Core change tracking are understood. Weitere Informationen zu diesen Themen finden Sie unter Änderungsnachverfolgung in EF Core .See Change Tracking in EF Core for more information on these topics.

Tipp

Sie können den gesamten Code in diesem Dokument ausführen und Debuggen, indem Sie den Beispielcode von GitHub herunterladen.You can run and debug into all the code in this document by downloading the sample code from GitHub.

Verwenden von dbcontext. Entry-und entityentry-InstanzenUsing DbContext.Entry and EntityEntry instances

Für jede überwachte Entität verfolgt Entity Framework Core (EF Core) Folgendes:For each tracked entity, Entity Framework Core (EF Core) keeps track of:

  • Der Gesamtzustand der Entität.The overall state of the entity. Dies ist eine von Unchanged , Modified , Added oder Deleted . Weitere Informationen finden Sie unter Änderungsnachverfolgung in EF Core .This is one of Unchanged, Modified, Added, or Deleted; see Change Tracking in EF Core for more information.
  • Die Beziehungen zwischen überwachten Entitäten.The relationships between tracked entities. Beispielsweise der Blog, zu dem ein Beitrag gehört.For example, the blog to which a post belongs.
  • Die "aktuellen Werte" von Eigenschaften.The "current values" of properties.
  • Die "ursprünglichen Werte" der Eigenschaften, wenn diese Informationen verfügbar sind.The "original values" of properties, when this information is available. Ursprüngliche Werte sind die Eigenschaftswerte, die vorhanden waren, als die Entität von der Datenbank abgefragt wurde.Original values are the property values that existed when entity was queried from the database.
  • Welche Eigenschaftswerte geändert wurden, seit Sie abgefragt wurden.Which property values have been modified since they were queried.
  • Weitere Informationen zu Eigenschafts Werten, z. b. ob der Wert temporärist oder nicht.Other information about property values, such as whether or not the value is temporary.

Das übergeben einer Entitäts Instanz an führt dazu, DbContext.Entry EntityEntry<TEntity> dass ein Zugriff auf diese Informationen für die angegebene Entität bereitstellt.Passing an entity instance to DbContext.Entry results in an EntityEntry<TEntity> providing access to this information for the given entity. Beispiel:For example:

using var context = new BlogsContext();

var blog = context.Blogs.Single(e => e.Id == 1);
var entityEntry = context.Entry(blog);

In den folgenden Abschnitten wird gezeigt, wie ein entityentry verwendet wird, um auf den Entitäts Status zuzugreifen und ihn zu bearbeiten, sowie den Zustand der Eigenschaften und Navigationen der Entität.The following sections show how to use an EntityEntry to access and manipulate entity state, as well as the state of the entity's properties and navigations.

Arbeiten mit der EntitätWorking with the entity

Die häufigste Verwendung von EntityEntry<TEntity> ist der Zugriff auf den aktuellen EntityState einer Entität.The most common use of EntityEntry<TEntity> is to access the current EntityState of an entity. Beispiel:For example:

var currentState = context.Entry(blog).State;
if (currentState == EntityState.Unchanged)
{
    context.Entry(blog).State = EntityState.Modified;
}

Die Entry-Methode kann auch für Entitäten verwendet werden, die noch nicht nachverfolgt wurden.The Entry method can also be used on entities that are not yet tracked. Dadurch wird die Nachverfolgung der Entität nicht gestartet. der Zustand der Entität ist weiterhin Detatched .This does not start tracking the entity; the state of the entity is still Detatched. Der zurückgegebene entityentry kann jedoch verwendet werden, um den Entitäts Status zu ändern. an diesem Punkt wird die Entität im angegebenen Zustand nachverfolgt.However, the returned EntityEntry can then be used to change the entity state, at which point the entity will become tracked in the given state. Mit dem folgenden Code wird beispielsweise die Nachverfolgung einer Blog Instanz wie folgt gestartet Added :For example, the following code will start tracking a Blog instance as Added:

var newBlog = new Blog();
Debug.Assert(context.Entry(newBlog).State == EntityState.Detached);

context.Entry(newBlog).State = EntityState.Added;
Debug.Assert(context.Entry(newBlog).State == EntityState.Added);

Tipp

Anders als bei EF6 führt das Festlegen des Zustands einer einzelnen Entität nicht dazu, dass alle verbundenen Entitäten nachverfolgt werden.Unlike in EF6, setting the state of an individual entity will not cause all connected entities to be tracked. Dies bewirkt, dass der Zustand auf die gleiche Weise als ein Vorgang auf niedrigerer Ebene festgelegt wird, der Add Attach Update auf ein gesamtes Diagramm von Entitäten angewendet wird.This makes setting the state this way a lower-level operation than calling Add, Attach, or Update, which operate on an entire graph of entities.

In der folgenden Tabelle sind die Möglichkeiten für die Verwendung eines entityentry zum Arbeiten mit einer gesamten Entität zusammengefasst:The following table summarizes ways to use an EntityEntry to work with an entire entity:

Entityentry-MemberEntityEntry member BESCHREIBUNGDescription
EntityEntry.State Ruft den der Entität ab und legt ihn fest EntityState .Gets and sets the EntityState of the entity.
EntityEntry.Entity Ruft die Entitäts Instanz ab.Gets the entity instance.
EntityEntry.Context Der DbContext , der diese Entität nachverfolgt.The DbContext that is tracking this entity.
EntityEntry.Metadata IEntityType Metadaten für den Entitätstyp.IEntityType metadata for the type of entity.
EntityEntry.IsKeySet Gibt an, ob für die Entität der Schlüsselwert festgelegt wurde.Whether or not the entity has had its key value set.
EntityEntry.Reload() Überschreibt Eigenschaftswerte mit aus der Datenbank gelesenen Werten.Overwrites property values with values read from the database.
EntityEntry.DetectChanges() Erzwingt nur das Erkennen von Änderungen für diese Entität. siehe Änderungs Erkennung und Benachrichtigungen.Forces detection of changes for this entity only; see Change Detection and Notifications.

Arbeiten mit einer einzelnen EigenschaftWorking with a single property

Mehrere über Ladungen von EntityEntry<TEntity>.Property ermöglichen den Zugriff auf Informationen über eine einzelne Eigenschaft einer Entität.Several overloads of EntityEntry<TEntity>.Property allow access to information about an individual property of an entity. Verwenden Sie beispielsweise eine stark typisierte, fließend ähnliche API:For example, using a strongly-typed, fluent-like API:

PropertyEntry<Blog, string> propertyEntry = context.Entry(blog).Property(e => e.Name);

Der Eigenschaftsname kann stattdessen als Zeichenfolge übermittelt werden.The property name can instead be passed as a string. Beispiel:For example:

PropertyEntry<Blog, string> propertyEntry = context.Entry(blog).Property<string>("Name");

Der zurückgegebene PropertyEntry<TEntity,TProperty> kann dann verwendet werden, um auf Informationen über die Eigenschaft zuzugreifen.The returned PropertyEntry<TEntity,TProperty> can then be used to access information about the property. Beispielsweise kann Sie verwendet werden, um den aktuellen Wert der-Eigenschaft für diese Entität zu erhalten und festzulegen:For example, it can be used to get and set the current value of the property on this entity:

string currentValue = context.Entry(blog).Property(e => e.Name).CurrentValue;
context.Entry(blog).Property(e => e.Name).CurrentValue = "1unicorn2";

Beide oben verwendeten Eigenschaften Methoden geben eine stark typisierte generische Instanz zurück PropertyEntry<TEntity,TProperty> .Both of the Property methods used above return a strongly-typed generic PropertyEntry<TEntity,TProperty> instance. Die Verwendung dieses generischen Typs wird bevorzugt, da Sie den Zugriff auf Eigenschaftswerte ohne Boxing-Werttypenzulässt.Using this generic type is preferred because it allows access to property values without boxing value types. Wenn der Typ der Entität oder Eigenschaft jedoch zur Kompilierzeit nicht bekannt ist, kann stattdessen ein nicht generischer Wert PropertyEntry abgerufen werden:However, if the type of entity or property is not known at compile-time, then a non-generic PropertyEntry can be obtained instead:

PropertyEntry propertyEntry = context.Entry(blog).Property("Name");

Dies ermöglicht den Zugriff auf Eigenschafts Informationen für jede Eigenschaft, unabhängig vom Typ, auf der Kosten der Boxing-Werttypen.This allows access to property information for any property regardless of its type, at the expense of boxing value types. Beispiel:For example:

object blog = context.Blogs.Single(e => e.Id == 1);

object currentValue = context.Entry(blog).Property("Name").CurrentValue;
context.Entry(blog).Property("Name").CurrentValue = "1unicorn2";

In der folgenden Tabelle werden die von PropertyEntry verfügbar gemachten Eigenschaften Informationen zusammengefasst:The following table summarizes property information exposed by PropertyEntry:

PropertyEntry-MemberPropertyEntry member BESCHREIBUNGDescription
PropertyEntry<TEntity,TProperty>.CurrentValue Ruft den aktuellen Wert der-Eigenschaft ab und legt diesen fest.Gets and sets the current value of the property.
PropertyEntry<TEntity,TProperty>.OriginalValue Ruft den ursprünglichen Wert der Eigenschaft ab, sofern verfügbar, oder legt ihn fest.Gets and sets the original value of the property, if available.
PropertyEntry<TEntity,TProperty>.EntityEntry Ein Rück Verweis auf die EntityEntry<TEntity> für die Entität.A back reference to the EntityEntry<TEntity> for the entity.
PropertyEntry.Metadata IProperty Metadaten für die Eigenschaft.IProperty metadata for the property.
PropertyEntry.IsModified Gibt an, ob diese Eigenschaft als geändert markiert ist, und ermöglicht es, diesen Zustand zu ändern.Indicates whether this property is marked as modified, and allows this state to be changed.
PropertyEntry.IsTemporary Gibt an, ob diese Eigenschaft als temporärmarkiert ist, und ermöglicht es, diesen Zustand zu ändern.Indicates whether this property is marked as temporary, and allows this state to be changed.

Hinweise:Notes:

  • Der ursprüngliche Wert einer Eigenschaft ist der Wert, den die Eigenschaft enthielt, als die Entität von der Datenbank abgefragt wurde.The original value of a property is the value that the property had when the entity was queried from the database. Ursprüngliche Werte sind jedoch nicht verfügbar, wenn die Entität getrennt und dann explizit an einen anderen dbcontext angefügt wurde, Attach z Update . b. mit oder.However, original values are not available if the entity was disconnected and then explicitly attached to another DbContext, for example with Attach or Update. In diesem Fall ist der ursprüngliche Wert, der zurückgegeben wird, mit dem aktuellen Wert identisch.In this case, the original value returned will be the same as the current value.
  • SaveChanges aktualisiert nur Eigenschaften, die als geändert markiert sind.SaveChanges will only update properties marked as modified. Legen Sie IsModified EF Core diese Eigenschaft auf "true" fest, um EF Core zu erzwingen, dass ein bestimmter Eigenschafts Wert aktualisiert wird.Set IsModified to true to force EF Core to update a given property value, or set it to false to prevent EF Core from updating the property value.
  • Temporäre Werte werden in der Regel von EF Core Wert Generatorengeneriert.Temporary values are typically generated by EF Core value generators. Wenn Sie den aktuellen Wert einer Eigenschaft festlegen, wird der temporäre Wert durch den angegebenen Wert ersetzt, und die Eigenschaft wird als nicht temporär markiert.Setting the current value of a property will replace the temporary value with the given value and mark the property as not temporary. Legen Sie diese Einstellung auf "true" fest IsTemporary , um zu erzwingen, dass ein Wert temporär ist, auch wenn er explizitSet IsTemporary to true to force a value to be temporary even after it has been explicitly set.

Arbeiten mit einer einzelnen NavigationWorking with a single navigation

Mehrere über Ladungen von EntityEntry<TEntity>.Reference , EntityEntry<TEntity>.Collection und EntityEntry.Navigation ermöglichen den Zugriff auf Informationen über eine einzelne Navigation.Several overloads of EntityEntry<TEntity>.Reference, EntityEntry<TEntity>.Collection, and EntityEntry.Navigation allow access to information about an individual navigation.

Der Zugriff auf die Verweis Navigation zu einer einzelnen verknüpften Entität erfolgt über die- Reference Methoden.Reference navigations to a single related entity are accessed through the Reference methods. Die Verweis Navigation verweist auf die 1-Seite der 1: n-Beziehungen und beide Seiten von 1: eins-Beziehungen.Reference navigations point to the "one" sides of one-to-many relationships, and both sides of one-to-one relationships. Beispiel:For example:

ReferenceEntry<Post, Blog> referenceEntry1 = context.Entry(post).Reference(e => e.Blog);
ReferenceEntry<Post, Blog> referenceEntry2 = context.Entry(post).Reference<Blog>("Blog");
ReferenceEntry referenceEntry3 = context.Entry(post).Reference("Blog");

Navigationen können auch Auflistungen verwandter Entitäten sein, wenn Sie für die "vielen" Seiten von 1: n-und m:n-Beziehungen verwendet werden.Navigations can also be collections of related entities when used for the "many" sides of one-to-many and many-to-many relationships. Die- Collection Methoden werden für den Zugriff auf Auflistungs Navigation verwendet.The Collection methods are used to access collection navigations. Beispiel:For example:

CollectionEntry<Blog, Post> collectionEntry1 = context.Entry(blog).Collection(e => e.Posts);
CollectionEntry<Blog, Post> collectionEntry2 = context.Entry(blog).Collection<Post>("Posts");
CollectionEntry collectionEntry3 = context.Entry(blog).Collection("Posts");

Einige Vorgänge sind für alle Navigationen üblich.Some operations are common for all navigations. Auf diese kann über die-Methode sowohl für Verweis-als auch Auflistungs Navigation zugegriffen werden EntityEntry.Navigation .These can be accessed for both reference and collection navigations using the EntityEntry.Navigation method. Beachten Sie, dass nur nicht generischer Zugriff verfügbar ist, wenn Sie auf alle Navigations Zugriffen zugreifen.Note that only non-generic access is available when accessing all navigations together. Beispiel:For example:

NavigationEntry navigationEntry = context.Entry(blog).Navigation("Posts");

In der folgenden Tabelle sind die Verwendungsmöglichkeiten von ReferenceEntry<TEntity,TProperty> , und zusammengefasst CollectionEntry<TEntity,TRelatedEntity> NavigationEntry :The following table summarizes ways to use ReferenceEntry<TEntity,TProperty>, CollectionEntry<TEntity,TRelatedEntity>, and NavigationEntry:

Navigationentry-MemberNavigationEntry member BESCHREIBUNGDescription
MemberEntry.CurrentValue Ruft den aktuellen Wert der Navigation ab und legt diesen fest.Gets and sets the current value of the navigation. Dies ist die gesamte Sammlung für Auflistungs Navigation.This is the entire collection for collection navigations.
NavigationEntry.Metadata INavigationBase Metadaten für die Navigation.INavigationBase metadata for the navigation.
NavigationEntry.IsLoaded Dient zum Abrufen oder Festlegen eines Werts, der angibt, ob die verknüpfte Entität oder Auflistung vollständig aus der Datenbank geladen wurde.Gets or sets a value indicating whether the related entity or collection has been fully loaded from the database.
NavigationEntry.Load() Lädt die verknüpfte Entität oder Auflistung aus der Datenbank. siehe Explizites Laden verwandter Daten.Loads the related entity or collection from the database; see Explicit Loading of Related Data.
NavigationEntry.Query() Die Abfrage EF Core würde verwenden, um diese Navigation als zu laden IQueryable , der weiter zusammengesetzt werden kann. siehe Explizites Ladenverknüpfter Daten.The query EF Core would use to load this navigation as an IQueryable that can be further composed; see Explicit Loading of Related Data.

Arbeiten mit allen Eigenschaften einer EntitätWorking with all properties of an entity

EntityEntry.Properties gibt eine IEnumerable<T> von PropertyEntry für jede Eigenschaft der Entität zurück.EntityEntry.Properties returns an IEnumerable<T> of PropertyEntry for every property of the entity. Dies kann verwendet werden, um eine Aktion für jede Eigenschaft der Entität auszuführen.This can be used to perform an action for every property of the entity. So legen Sie beispielsweise eine beliebige DateTime-Eigenschaft auf fest DateTime.Now :For example, to set any DateTime property to DateTime.Now:

foreach (var propertyEntry in context.Entry(blog).Properties)
{
    if (propertyEntry.Metadata.ClrType == typeof(DateTime))
    {
        propertyEntry.CurrentValue = DateTime.Now;
    }
}

Außerdem enthält entityentry mehrere Methoden, um alle Eigenschaftswerte gleichzeitig zu erhalten und festzulegen.In addition, EntityEntry contains several methods to get and set all property values at the same time. Diese Methoden verwenden die PropertyValues -Klasse, die eine Auflistung von Eigenschaften und deren Werten darstellt.These methods use the PropertyValues class, which represents a collection of properties and their values. PropertyValues können für die aktuellen oder ursprünglichen Werte oder für die Werte abgerufen werden, die derzeit in der Datenbank gespeichert sind.PropertyValues can be obtained for current or original values, or for the values as currently stored in the database. Beispiel:For example:

var currentValues = context.Entry(blog).CurrentValues;
var originalValues = context.Entry(blog).OriginalValues;
var databaseValues = context.Entry(blog).GetDatabaseValues();

Diese propertyValues-Objekte sind selbst nicht sehr nützlich.These PropertyValues objects are not very useful on their own. Allerdings können Sie kombiniert werden, um allgemeine Vorgänge auszuführen, die beim Bearbeiten von Entitäten erforderlich sind.However, they can be combined to perform common operations needed when manipulating entities. Dies ist nützlich, wenn Sie mit Datenübertragungs Objekten arbeiten und Konflikte mit optimistischerParallelität lösen.This is useful when working with data transfer objects and when resolving optimistic concurrency conflicts. In den folgenden Abschnitten werden einige Beispiele gezeigt.The following sections show some examples.

Festlegen aktueller oder ursprünglicher Werte aus einer Entität oder einem DTOSetting current or original values from an entity or DTO

Die aktuellen oder ursprünglichen Werte einer Entität können aktualisiert werden, indem Werte aus einem anderen Objekt kopiert werden.The current or original values of an entity can be updated by copying values from another object. Angenommen, ein BlogDto Datenübertragungs Objekt (Data Transfer Object, dto) mit denselben Eigenschaften wie der Entitätstyp:For example, consider a BlogDto data transfer object (DTO) with the same properties as the entity type:

public class BlogDto
{
    public int Id { get; set; }
    public string Name { get; set; }
}

Dies kann verwendet werden, um die aktuellen Werte einer nach verfolgten Entität mit festzulegen PropertyValues.SetValues :This can be used to set the current values of a tracked entity using PropertyValues.SetValues:

var blogDto = new BlogDto { Id = 1, Name = "1unicorn2" };

context.Entry(blog).CurrentValues.SetValues(blogDto);

Diese Technik wird manchmal beim Aktualisieren einer Entität mit Werten verwendet, die von einem Dienst-oder Client in einer n-Tier-Anwendung abgerufen werden.This technique is sometimes used when updating an entity with values obtained from a service call or a client in an n-tier application. Beachten Sie, dass das verwendete Objekt nicht denselben Typ wie die Entität aufweisen muss, solange es über Eigenschaften verfügt, deren Namen mit denen der Entität übereinstimmen.Note that the object used does not have to be of the same type as the entity so long as it has properties whose names match those of the entity. Im obigen Beispiel wird eine Instanz des DTO-Werts BlogDto verwendet, um die aktuellen Werte einer nach verfolgten Blog Entität festzulegen.In the example above, an instance of the DTO BlogDto is used to set the current values of a tracked Blog entity.

Beachten Sie, dass Eigenschaften nur als geändert gekennzeichnet werden, wenn sich der festgelegte Wert vom aktuellen Wert unterscheidet.Note that properties will only be marked as modified if the value set differs from the current value.

Festlegen aktueller oder ursprünglicher Werte aus einem WörterbuchSetting current or original values from a dictionary

Im vorherigen Beispiel wurden Werte aus einer Entität oder einer DTO-Instanz festgelegt.The previous example set values from an entity or DTO instance. Das gleiche Verhalten ist verfügbar, wenn Eigenschaftswerte als Name-Wert-Paare in einem Wörterbuch gespeichert werden.The same behavior is available when property values are stored as name/value pairs in a dictionary. Beispiel:For example:

var blogDictionary = new Dictionary<string, object> { ["Id"] = 1, ["Name"] = "1unicorn2" };

context.Entry(blog).CurrentValues.SetValues(blogDictionary);

Festlegen aktueller oder ursprünglicher Werte aus der DatenbankSetting current or original values from the database

Die aktuellen oder ursprünglichen Werte einer Entität können mit den neuesten Werten aus der Datenbank aktualisiert werden, indem GetDatabaseValues() oder aufgerufen GetDatabaseValuesAsync und das zurückgegebene-Objekt verwendet wird, um aktuelle oder ursprüngliche Werte festzulegen, oder beides.The current or original values of an entity can be updated with the latest values from the database by calling GetDatabaseValues() or GetDatabaseValuesAsync and using the returned object to set current or original values, or both. Beispiel:For example:

var databaseValues = context.Entry(blog).GetDatabaseValues();
context.Entry(blog).CurrentValues.SetValues(databaseValues);
context.Entry(blog).OriginalValues.SetValues(databaseValues);

Erstellen eines geklonten Objekts mit aktuellen, ursprünglichen oder Daten bankwertenCreating a cloned object containing current, original, or database values

Das propertyValues-Objekt, das von CurrentValues, OriginalValues oder getdatabasevalues zurückgegeben wird, kann verwendet werden, um mithilfe von einen Klon der Entität zu erstellen PropertyValues.ToObject() .The PropertyValues object returned from CurrentValues, OriginalValues, or GetDatabaseValues can be used to create a clone of the entity using PropertyValues.ToObject(). Beispiel:For example:

var clonedBlog = context.Entry(blog).GetDatabaseValues().ToObject();

Beachten Sie, dass ToObject eine neue-Instanz zurückgibt, die nicht von dbcontext nachverfolgt wird.Note that ToObject returns a new instance that is not tracked by the DbContext. Für das zurückgegebene Objekt sind auch keine Beziehungen auf andere Entitäten festgelegt.The returned object also does not have any relationships set to other entities.

Das geklonte Objekt kann nützlich sein, um Probleme im Zusammenhang mit gleichzeitigen Aktualisierungen der Datenbank zu beheben, insbesondere bei der Datenbindung an Objekte eines bestimmten Typs.The cloned object can be useful for resolving issues related to concurrent updates to the database, especially when data binding to objects of a certain type. Weitere Informationen finden Sie unter vollständige Parallelität.See optimistic concurrency for more information.

Arbeiten mit allen Navigationen einer EntitätWorking with all navigations of an entity

EntityEntry.Navigations Gibt einen IEnumerable<T> von NavigationEntry für jede Navigation der Entität zurück.EntityEntry.Navigations returns an IEnumerable<T> of NavigationEntry for every navigation of the entity. EntityEntry.References und EntityEntry.Collections führen Sie dasselbe aus, aber beschränkt auf Verweis-bzw. Sammlungs Navigation.EntityEntry.References and EntityEntry.Collections do the same thing, but restricted to reference or collection navigations respectively. Dies kann verwendet werden, um eine Aktion für jede Navigation der Entität auszuführen.This can be used to perform an action for every navigation of the entity. So erzwingen Sie z. b. das Laden aller zugehörigen Entitäten:For example, to force loading of all related entities:

foreach (var navigationEntry in context.Entry(blog).Navigations)
{
    navigationEntry.Load();
}

Arbeiten mit allen Membern einer EntitätWorking with all members of an entity

Reguläre Eigenschaften und Navigations Eigenschaften haben unterschiedliche Zustände und Verhalten.Regular properties and navigation properties have different state and behavior. Es ist daher üblich, Navigationen und nicht-Navigationen separat zu verarbeiten, wie in den obigen Abschnitten gezeigt.It is therefore common to process navigations and non-navigations separately, as shown in the sections above. Manchmal kann es jedoch nützlich sein, etwas mit einem beliebigen Member der Entität durchzuführen, unabhängig davon, ob es sich um eine reguläre Eigenschaft oder Navigation handelt.However, sometimes it can be useful to do something with any member of the entity, regardless of whether it is a regular property or navigation. EntityEntry.Member und EntityEntry.Members werden zu diesem Zweck bereitgestellt.EntityEntry.Member and EntityEntry.Members are provided for this purpose. Beispiel:For example:

foreach (var memberEntry in context.Entry(blog).Members)
{
    Console.WriteLine(
        $"Member {memberEntry.Metadata.Name} is of type {memberEntry.Metadata.ClrType.ShortDisplayName()} and has value {memberEntry.CurrentValue}");
}

Wenn Sie diesen Code in einem Blog aus dem Beispiel ausführen, wird die folgende Ausgabe generiert:Running this code on a blog from the sample generates the following output:

Member Id is of type int and has value 1
Member Name is of type string and has value .NET Blog
Member Posts is of type IList<Post> and has value System.Collections.Generic.List`1[Post]

Tipp

In der Debugansicht Änderungs nach Verfolgung werden Informationen wie diese angezeigt.The change tracker debug view shows information like this. Die Debugansicht für die gesamte Änderungs Nachverfolgung wird von der einzelnen einzelnen nach EntityEntry.DebugView verfolgten Entität generiert.The debug view for the entire change tracker is generated from the individual EntityEntry.DebugView of each tracked entity.

Suchen und FindAsyncFind and FindAsync

DbContext.Find, DbContext.FindAsync , DbSet<TEntity>.Find und DbSet<TEntity>.FindAsync sind für die effiziente Suche einer einzelnen Entität konzipiert, wenn der primäre Schlüssel bekannt ist.DbContext.Find, DbContext.FindAsync, DbSet<TEntity>.Find, and DbSet<TEntity>.FindAsync are designed for efficient lookup of a single entity when its primary key is known. Sucht zuerst nach der Überprüfung, ob die Entität bereits nachverfolgt wird, und gibt dann die Entität sofort zurückFind first checks if the entity is already tracked, and if so returns the entity immediately. Eine Datenbankabfrage wird nur vorgenommen, wenn die Entität nicht lokal nachverfolgt wird.A database query is only made if the entity is not tracked locally. Sehen Sie sich beispielsweise den folgenden Code an, der die Suche zweimal für dieselbe Entität aufruft:For example, consider this code that calls Find twice for the same entity:

using var context = new BlogsContext();

Console.WriteLine("First call to Find...");
var blog1 = context.Blogs.Find(1);

Console.WriteLine($"...found blog {blog1.Name}");

Console.WriteLine();
Console.WriteLine("Second call to Find...");
var blog2 = context.Blogs.Find(1);
Debug.Assert(blog1 == blog2);

Console.WriteLine("...returned the same instance without executing a query.");

Die Ausgabe dieses Codes (einschließlich EF Core Protokollierung) bei Verwendung von SQLite lautet wie folgt:The output from this code (including EF Core logging) when using SQLite is:

First call to Find...
info: 12/29/2020 07:45:53.682 RelationalEventId.CommandExecuted[20101] (Microsoft.EntityFrameworkCore.Database.Command)
      Executed DbCommand (1ms) [Parameters=[@__p_0='1' (DbType = String)], CommandType='Text', CommandTimeout='30']
      SELECT "b"."Id", "b"."Name"
      FROM "Blogs" AS "b"
      WHERE "b"."Id" = @__p_0
      LIMIT 1
...found blog .NET Blog

Second call to Find...
...returned the same instance without executing a query.

Beachten Sie, dass der erste-Befehl die Entität nicht lokal findet und somit eine Datenbankabfrage ausführt.Notice that the first call does not find the entity locally and so executes a database query. Umgekehrt gibt der zweite-Befehl dieselbe Instanz zurück, ohne die Datenbank abzufragen, weil Sie bereits nachverfolgt wird.Conversely, the second call returns the same instance without querying the database because it is already being tracked.

Find gibt NULL zurück, wenn eine Entität mit dem angegebenen Schlüssel nicht lokal nachverfolgt wird und nicht in der Datenbank vorhanden ist.Find returns null if an entity with the given key is not tracked locally and does not exist in the database.

Zusammengesetzte SchlüsselComposite keys

Find kann auch mit zusammengesetzten Schlüsseln verwendet werden.Find can also be used with composite keys. Stellen Sie sich beispielsweise eine OrderLine Entität mit einem zusammengesetzten Schlüssel vor, der aus der Bestell-ID und der Produkt-ID besteht:For example, consider an OrderLine entity with a composite key consisting of the order ID and the product ID:

public class OrderLine
{
    public int OrderId { get; set; }
    public int ProductId { get; set; }

    //...
}

Der zusammengesetzte Schlüssel muss in konfiguriert werden DbContext.OnModelCreating , um die Schlüsselteile und deren Reihenfolge zu definieren.The composite key must be configured in DbContext.OnModelCreating to define the key parts and their order. Beispiel:For example:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder
        .Entity<OrderLine>()
        .HasKey(e => new { e.OrderId, e.ProductId });
}

Beachten Sie, dass OrderId der erste Teil des Schlüssels und ProductId der zweite Teil des Schlüssels ist.Notice that OrderId is the first part of the key and ProductId is the second part of the key. Diese Reihenfolge muss beim Übergeben von Schlüsselwerten für die Suche verwendet werden.This order must be used when passing key values to Find. Beispiel:For example:

var orderline = context.OrderLines.Find(orderId, productId);

Verwenden von ChangeTracker. Entries für den Zugriff auf alle nach verfolgten EntitätenUsing ChangeTracker.Entries to access all tracked entities

Bisher haben wir nur jeweils ein einzelnes-Paar aufgerufen EntityEntry .So far we have accessed only a single EntityEntry at a time. ChangeTracker.Entries() Gibt einen entityentry für jede Entität zurück, die derzeit von dbcontext nachverfolgt wird.ChangeTracker.Entries() returns an EntityEntry for every entity currently tracked by the DbContext. Beispiel:For example:

using var context = new BlogsContext();
var blogs = context.Blogs.Include(e => e.Posts).ToList();

foreach (var entityEntry in context.ChangeTracker.Entries())
{
    Console.WriteLine($"Found {entityEntry.Metadata.Name} entity with ID {entityEntry.Property("Id").CurrentValue}");
}

Dieser Code generiert die folgende Ausgabe:This code generates the following output:

Found Blog entity with ID 1
Found Post entity with ID 1
Found Post entity with ID 2

Beachten Sie, dass Einträge für beide Blogs und Beiträge zurückgegeben werden.Notice that entries for both blogs and posts are returned. Die Ergebnisse können stattdessen mithilfe der generischen Überladung zu einem bestimmten Entitätstyp gefiltert werden ChangeTracker.Entries<TEntity>() :The results can instead be filtered to a specific entity type using the ChangeTracker.Entries<TEntity>() generic overload:

foreach (var entityEntry in context.ChangeTracker.Entries<Post>())
{
    Console.WriteLine(
        $"Found {entityEntry.Metadata.Name} entity with ID {entityEntry.Property(e => e.Id).CurrentValue}");
}

Die Ausgabe dieses Codes zeigt, dass nur Beiträge zurückgegeben werden:The output from this code shows that only posts are returned:

Found Post entity with ID 1
Found Post entity with ID 2

Außerdem gibt die generische Überladung generische EntityEntry<TEntity> Instanzen zurück.Also, using the generic overload returns generic EntityEntry<TEntity> instances. Dies ermöglicht es, dass in diesem Beispiel ein fließend ähnlicher Zugriff auf die-Eigenschaft möglich ist Id .This is what allows that fluent-like access to the Id property in this example.

Der zum Filtern verwendete generische Typ muss kein zugeordneter Entitätstyp sein. Stattdessen kann ein nicht zugeordneter Basistyp oder eine nicht zugeordnete Schnittstelle verwendet werdenThe generic type used for filtering does not have to be a mapped entity type; an unmapped base type or interface can be used instead. Wenn z. b. alle Entitäts Typen im Modell eine Schnittstelle implementieren, die ihre Schlüsseleigenschaft definiert:For example, if all the entity types in the model implement an interface defining their key property:

public interface IEntityWithKey
{
    int Id { get; set; }
}

Diese Schnittstelle kann dann verwendet werden, um mit dem Schlüssel einer nach verfolgten Entität in einer stark typisierten Weise zu arbeiten.Then this interface can be used to work with the key of any tracked entity in a strongly-typed manner. Beispiel:For example:

foreach (var entityEntry in context.ChangeTracker.Entries<IEntityWithKey>())
{
    Console.WriteLine(
        $"Found {entityEntry.Metadata.Name} entity with ID {entityEntry.Property(e => e.Id).CurrentValue}");
}

Abfragen von nach verfolgten Entitäten mithilfe von "dbset. local"Using DbSet.Local to query tracked entities

EF Core Abfragen werden stets für die Datenbank ausgeführt, und es werden nur Entitäten zurückgegeben, die in der Datenbank gespeichert wurden.EF Core queries are always executed on the database, and only return entities that have been saved to the database. DbSet<TEntity>.Local stellt einen Mechanismus zum Abfragen von dbcontext für lokale, nach verfolgte Entitäten bereit.DbSet<TEntity>.Local provides a mechanism to query the DbContext for local, tracked entities.

Da DbSet.Local verwendet wird, um nach verfolgte Entitäten abzufragen, ist es typisch, Entitäten in den dbcontext zu laden und dann mit diesen geladenen Entitäten zu arbeiten.Since DbSet.Local is used to query tracked entities, it is typical to load entities into the DbContext and then work with those loaded entities. Dies gilt insbesondere für die Datenbindung, kann aber auch in anderen Situationen nützlich sein.This is especially true for data binding, but can also be useful in other situations. Im folgenden Code wird die Datenbank z. b. zuerst nach allen Blogs und Beiträgen abgefragt.For example, in the following code the database is first queried for all blogs and posts. Die- Load Erweiterungsmethode wird verwendet, um diese Abfrage mit den vom Kontext nach verfolgten Ergebnissen auszuführen, ohne direkt an die Anwendung zurückgegeben zu werden.The Load extension method is used to execute this query with the results tracked by the context without being returned directly to the application. (Die Verwendung ToList von oder ähnlichem hat denselben Effekt, aber mit dem Aufwand zum Erstellen der zurückgegebenen Liste, der hier nicht benötigt wird.) Im Beispiel wird dann verwendet DbSet.Local , um auf die lokal überwachten Entitäten zuzugreifen:(Using ToList or similar has the same effect but with the overhead of creating the returned list, which is not needed here.) The example then uses DbSet.Local to access the locally tracked entities:

using var context = new BlogsContext();

context.Blogs.Include(e => e.Posts).Load();

foreach (var blog in context.Blogs.Local)
{
    Console.WriteLine($"Blog: {blog.Name}");
}

foreach (var post in context.Posts.Local)
{
    Console.WriteLine($"Post: {post.Title}");
}

Beachten Sie, dass im Gegensatz zu ChangeTracker.Entries() DbSet.Local Entitäts Instanzen direkt zurückgibt.Notice that, unlike ChangeTracker.Entries(), DbSet.Local returns entity instances directly. Ein entityentry kann natürlich immer für die zurückgegebene Entität abgerufen werden, indem aufgerufen wird DbContext.Entry .An EntityEntry can, of course, always be obtained for the returned entity by calling DbContext.Entry.

Die lokale AnsichtThe local view

DbSet<TEntity>.Local gibt eine Ansicht der lokal überwachten Entitäten zurück, die die aktuellen EntityState dieser Entitäten widerspiegeln.DbSet<TEntity>.Local returns a view of locally tracked entities that reflects the current EntityState of those entities. Dies bedeutet insbesondere Folgendes:Specifically, this means that:

  • Added Entitäten sind eingeschlossen.Added entities are included. Beachten Sie, dass dies für normale EF Core Abfragen nicht der Fall ist, da Added Entitäten noch nicht in der Datenbank vorhanden sind und daher nie von einer Datenbankabfrage zurückgegeben werden.Note that this is not the case for normal EF Core queries, since Added entities do not yet exist in the database and so are therefore never returned by a database query.
  • Deleted Entitäten werden ausgeschlossen.Deleted entities are excluded. Beachten Sie, dass dies für normale EF Core Abfragen noch nicht der Fall ist, da Deleted Entitäten in der Datenbank noch vorhanden sind und von Datenbankabfragen zurückgegeben werden .Note that this is again not the case for normal EF Core queries, since Deleted entities still exist in the database and so are returned by database queries.

Dies bedeutet, dass DbSet.Local die Daten anzeigen, die den aktuellen konzeptionellen Zustand des Entitäts Diagramms widerspiegeln, wobei Added enthaltene Entitäten und Deleted Entitäten ausgeschlossen sind.All of this means that DbSet.Local is view over the data that reflects the current conceptual state of the entity graph, with Added entities included and Deleted entities excluded. Dies entspricht dem Namen des Daten Bank Zustands, der nach dem Aufruf von SaveChanges erwartet wird.This matches what database state is expected to be after SaveChanges is called.

Dies ist in der Regel die ideale Ansicht für die Datenbindung, da dem Benutzer die Daten entsprechend den von der Anwendung vorgenommenen Änderungen angezeigt werden.This is typically the ideal view for data binding, since it presents to the user the data as they understand it based on the changes made by the application.

Der folgende Code zeigt, wie ich einen Beitrag als markiere Deleted und dann einen neuen Beitrag zufüge. AddedThe following code demonstrates this my marking one post as Deleted and then adding a new post, marking it as Added:

using var context = new BlogsContext();

var posts = context.Posts.Include(e => e.Blog).ToList();

Console.WriteLine("Local view after loading posts:");

foreach (var post in context.Posts.Local)
{
    Console.WriteLine($"  Post: {post.Title}");
}

context.Remove(posts[1]);

context.Add(
    new Post
    {
        Title = "What’s next for System.Text.Json?",
        Content = ".NET 5.0 was released recently and has come with many...",
        Blog = posts[0].Blog
    });

Console.WriteLine("Local view after adding and deleting posts:");

foreach (var post in context.Posts.Local)
{
    Console.WriteLine($"  Post: {post.Title}");
}

Die Ausgabe dieses Codes lautet wie folgt:The output from this code is:

Local view after loading posts:
  Post: Announcing the Release of EF Core 5.0
  Post: Announcing F# 5
  Post: Announcing .NET 5.0
Local view after adding and deleting posts:
  Post: What’s next for System.Text.Json?
  Post: Announcing the Release of EF Core 5.0
  Post: Announcing .NET 5.0

Beachten Sie, dass der gelöschte Beitrag aus der lokalen Ansicht entfernt wird und der hinzugefügte Beitrag enthalten ist.Notice that the deleted post is removed from the local view, and the added post is included.

Verwenden von local zum Hinzufügen und Entfernen von EntitätenUsing Local to add and remove entities

DbSet<TEntity>.Local gibt eine Instanz von LocalView<TEntity> zurück.DbSet<TEntity>.Local returns an instance of LocalView<TEntity>. Dies ist eine Implementierung von ICollection<T> , die Benachrichtigungen generiert und antwortet, wenn Entitäten hinzugefügt und aus der Auflistung entfernt werden.This is an implementation of ICollection<T> that generates and responds to notifications when entities are added and removed from the collection. (Dies ist das gleiche Konzept wie ObservableCollection<T> , wird jedoch als Projektion über vorhandene EF Core Änderungs nach Verfolgungs Einträge implementiert, nicht als unabhängige Sammlung.)(This is the same concept as ObservableCollection<T>, but implemented as a projection over existing EF Core change tracking entries, rather than as an independent collection.)

Die Benachrichtigungen der lokalen Ansicht werden mit der dbcontext-Änderungs Nachverfolgung verknüpft, sodass die lokale Ansicht mit dbcontext synchron bleibt.The local view's notifications are hooked into DbContext change tracking such that the local view stays in sync with the DbContext. Dies gilt insbesondere in folgenden Fällen:Specifically:

  • Wenn eine neue Entität hinzugefügt DbSet.Local wird, wird Sie von dbcontext nachverfolgt, in der Regel im- Added Zustand.Adding a new entity to DbSet.Local causes it to be tracked by the DbContext, typically in the Added state. (Wenn die Entität bereits einen generierten Schlüsselwert aufweist, wird Sie stattdessen als nachverfolgt Unchanged .)(If the entity already has a generated key value, then it is tracked as Unchanged instead.)
  • Wenn eine Entität aus entfernt DbSet.Local wird, wird Sie als gekennzeichnet Deleted .Removing an entity from DbSet.Local causes it to be marked as Deleted.
  • Eine Entität, die von dbcontext nachverfolgt wird, wird automatisch in der Auflistung angezeigt DbSet.Local .An entity that becomes tracked by the DbContext will automatically appear in the DbSet.Local collection. Wenn Sie z. b. eine Abfrage ausführen, um weitere Entitäten zu aktivieren, wird die lokale Ansicht aktualisiert.For example, executing a query to bring in more entities automatically causes the local view to be updated.
  • Eine Entität, die als markiert ist, Deleted wird automatisch aus der lokalen Auflistung entfernt.An entity that is marked as Deleted will be removed from the local collection automatically.

Dies bedeutet, dass die lokale Ansicht verwendet werden kann, um überwachte Entitäten einfach durch Hinzufügen und entfernen aus der Auflistung zu bearbeiten.This means the local view can be used to manipulate tracked entities simply by adding and removing from the collection. Beispielsweise können Sie den vorherigen Beispielcode ändern, um Beiträge in der lokalen Sammlung hinzuzufügen und zu entfernen:For example, lets modify the previous example code to add and remove posts from the local collection:

using var context = new BlogsContext();

var posts = context.Posts.Include(e => e.Blog).ToList();

Console.WriteLine("Local view after loading posts:");

foreach (var post in context.Posts.Local)
{
    Console.WriteLine($"  Post: {post.Title}");
}

context.Posts.Local.Remove(posts[1]);

context.Posts.Local.Add(
    new Post
    {
        Title = "What’s next for System.Text.Json?",
        Content = ".NET 5.0 was released recently and has come with many...",
        Blog = posts[0].Blog
    });

Console.WriteLine("Local view after adding and deleting posts:");

foreach (var post in context.Posts.Local)
{
    Console.WriteLine($"  Post: {post.Title}");
}

Die Ausgabe bleibt unverändert im vorherigen Beispiel, da an der lokalen Ansicht vorgenommene Änderungen mit dbcontext synchronisiert werden.The output remains unchanged from the previous example because changes made to the local view are synced with the DbContext.

Verwenden der lokalen Ansicht für Windows Forms-oder WPF-DatenbindungUsing the local view for Windows Forms or WPF data binding

DbSet<TEntity>.Local bildet die Basis für die Datenbindung an EF Core Entitäten.DbSet<TEntity>.Local forms the basis for data binding to EF Core entities. Allerdings funktionieren sowohl Windows Forms als auch WPF am besten, wenn Sie mit dem spezifischen Typ der Benachrichtigungs Sammlung verwendet werden, die Sie erwarten.However, both Windows Forms and WPF work best when used with the specific type of notifying collection that they expect. Die lokale Ansicht unterstützt das Erstellen dieser speziellen Sammlungs Typen:The local view supports creating these specific collection types:

Beispiel:For example:

ObservableCollection<Post> observableCollection = context.Posts.Local.ToObservableCollection();
BindingList<Post> bindingList = context.Posts.Local.ToBindingList();

Weitere Informationen zur WPF-Datenbindung mit EF Core finden Sie unter Get Started with WPF .See Get Started with WPF for more information on WPF data binding with EF Core.

Tipp

Die lokale Ansicht für eine bestimmte dbset-Instanz wird verzögert erstellt, wenn zuerst darauf zugegriffen und dann zwischengespeichert wird.The local view for a given DbSet instance is created lazily when first accessed and then cached. Die localview-Erstellung selbst ist schnell und verwendet keinen signifikanten Arbeitsspeicher.LocalView creation itself is fast and it does not use significant memory. Es wird jedoch " DetectChanges" aufgerufen, was für eine große Anzahl von Entitäten langsam sein kann.However, it does call DetectChanges, which can be slow for large numbers of entities. Die von und erstellten ToObservableCollection Sammlungen ToBindingList werden ebenfalls verzögert und dann zwischengespeichert.The collections created by ToObservableCollection and ToBindingList are also created lazily and and then cached. Beide Methoden erstellen neue Auflistungen, die langsam sein können und viel Arbeitsspeicher nutzen, wenn Tausende von Entitäten beteiligt sind.Both of these methods create new collections, which can be slow and use a lot of memory when thousands of entities are involved.