Änderungs nach Verfolgungs DebuggingChange Tracker Debugging

Der Änderungs Tracker Entity Framework Core (EF Core) generiert zwei Arten von Ausgaben, die beim Debuggen hilfreich sind:The Entity Framework Core (EF Core) change tracker generates two kinds of output to help with debugging:

  • ChangeTracker.DebugViewStellt eine lesbare Ansicht aller Entitäten bereit, die nachverfolgt werden.The ChangeTracker.DebugView provides a human-readable view of all entities being tracked
  • Protokollmeldungen auf Debugebene werden generiert, wenn die Änderungs Nachverfolgung den Status erkennt und Beziehungen korrigiert.Debug-level log messages are generated when the change tracker detects state and fixes up relationships

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.

Debug-Ansicht für Änderungs NachverfolgungChange tracker debug view

Sie können im Debugger Ihrer IDE auf die Debugansicht für die Änderungs Nachverfolgung zugreifen.The change tracker debug view can be accessed in the debugger of your IDE. Beispielsweise mit Visual Studio:For example, with Visual Studio:

Zugreifen auf die Debugansicht der Änderungs Nachverfolgung über den Visual Studio-Debugger

Sie können auch direkt über den Code darauf zugreifen, z. b. um die Debugansicht an die Konsole zu senden:It can also be accessed directly from code, for example to send the debug view to the console:

Console.WriteLine(context.ChangeTracker.DebugView.ShortView);

Die Debugansicht hat eine Kurzform und eine lange Form.The debug view has a short form and a long form. In der Kurzform werden nach verfolgte Entitäten, deren Status und Schlüsselwerte angezeigt.The short form shows tracked entities, their state, and key values. Die Long-Form umfasst auch alle Eigenschafts-und Navigations Werte und den Status.The long form also includes all property and navigation values and state.

Die kurze AnsichtThe short view

Sehen wir uns ein Beispiel für eine Debugansicht an, das das am Ende dieses Dokuments gezeigte Modell verwendet.Let's look at a debug view example using the model shown at the end of this document. Zunächst werden einige Entitäten nachverfolgt und in verschiedenen Zuständen abgelegt, damit wir gute Änderungs nach Verfolgungs Daten anzeigen können:First, we will track some entities and put them in some different states, just so we have good change tracking data to view:

using var context = new BlogsContext();

var blogs = context.Blogs
    .Include(e => e.Posts).ThenInclude(e => e.Tags)
    .Include(e => e.Assets)
    .ToList();

// Mark something Added
blogs[0].Posts.Add(
    new Post
    {
        Title = "What’s next for System.Text.Json?",
        Content = ".NET 5.0 was released recently and has come with many new features and..."
    });

// Mark something Deleted
blogs[1].Posts.Remove(blogs[1].Posts[1]);

// Make something Modified
blogs[0].Name = ".NET Blog (All new!)";

context.ChangeTracker.DetectChanges();

Das Drucken der kurzen Ansicht an dieser Stelle, wie oben gezeigt, führt zur folgenden Ausgabe:Printing the short view at this point, as shown above, results in the following output:

Blog {Id: 1} Modified AK {AssetsId: ed727978-1ffe-4709-baee-73913e8e44a0}
Blog {Id: 2} Unchanged AK {AssetsId: 3a54b880-2b9d-486b-9403-dc2e52d36d65}
BlogAssets {Id: 3a54b880-2b9d-486b-9403-dc2e52d36d65} Unchanged FK {Id: 3a54b880-2b9d-486b-9403-dc2e52d36d65}
BlogAssets {Id: ed727978-1ffe-4709-baee-73913e8e44a0} Unchanged FK {Id: ed727978-1ffe-4709-baee-73913e8e44a0}
Post {Id: -2147482643} Added FK {BlogId: 1}
Post {Id: 1} Unchanged FK {BlogId: 1}
Post {Id: 2} Unchanged FK {BlogId: 1}
Post {Id: 3} Unchanged FK {BlogId: 2}
Post {Id: 4} Deleted FK {BlogId: 2}
PostTag (Dictionary<string, object>) {PostsId: 1, TagsId: 1} Unchanged FK {PostsId: 1} FK {TagsId: 1}
PostTag (Dictionary<string, object>) {PostsId: 1, TagsId: 3} Unchanged FK {PostsId: 1} FK {TagsId: 3}
PostTag (Dictionary<string, object>) {PostsId: 2, TagsId: 1} Unchanged FK {PostsId: 2} FK {TagsId: 1}
PostTag (Dictionary<string, object>) {PostsId: 3, TagsId: 2} Unchanged FK {PostsId: 3} FK {TagsId: 2}
PostTag (Dictionary<string, object>) {PostsId: 4, TagsId: 2} Deleted FK {PostsId: 4} FK {TagsId: 2}
Tag {Id: 1} Unchanged
Tag {Id: 2} Unchanged
Tag {Id: 3} Unchanged

Beachten Sie Folgendes:Notice:

  • Jede nach verfolgte Entität wird mit ihrem Primärschlüssel Wert (PK) aufgelistet.Each tracked entity is listed with its primary key (PK) value. Beispiel: Blog {Id: 1}.For example, Blog {Id: 1}.
  • Wenn es sich bei der Entität um einen Entitätstyp mit gemeinsam genutzter Entität handelt, wird auch der CLR-Typ angezeigt.If the entity is a shared-type entity type, then it's CLR type is also shown. Beispiel: PostTag (Dictionary<string, object>).For example, PostTag (Dictionary<string, object>).
  • Der EntityState wird als nächstes angezeigt.The EntityState is shown next. Dabei handelt es sich um eine von Unchanged , Added , Modified oder Deleted .This will be one of Unchanged, Added, Modified, or Deleted.
  • Die Werte für beliebige Alternative Schlüssel (AKS) werden als nächstes angezeigt.Values for any alternate keys (AKs) are shown next. Beispiel: AK {AssetsId: ed727978-1ffe-4709-baee-73913e8e44a0}.For example, AK {AssetsId: ed727978-1ffe-4709-baee-73913e8e44a0}.
  • Schließlich werden die Werte für alle Fremdschlüssel (Key Keys, f) angezeigt.Finally, values for any foreign keys (FKs) are shown. Beispiel: FK {PostsId: 4} FK {TagsId: 2}.For example, FK {PostsId: 4} FK {TagsId: 2}.

Die lange AnsichtThe long view

Die Ansicht Long kann auf die gleiche Weise wie in der kurzen Ansicht an die Konsole gesendet werden:The long view can be sent to the console in the same way as the short view:

Console.WriteLine(context.ChangeTracker.DebugView.LongView);

Die Ausgabe für denselben Zustand wie die kurze Ansicht oben ist:The output for the same state as the short view above is:

Blog {Id: 1} Modified
  Id: 1 PK
  AssetsId: 'ed727978-1ffe-4709-baee-73913e8e44a0' AK
  Name: '.NET Blog (All new!)' Modified Originally '.NET Blog'
  Assets: {Id: ed727978-1ffe-4709-baee-73913e8e44a0}
  Posts: [{Id: 1}, {Id: 2}, {Id: -2147482643}]
Blog {Id: 2} Unchanged
  Id: 2 PK
  AssetsId: '3a54b880-2b9d-486b-9403-dc2e52d36d65' AK
  Name: 'Visual Studio Blog'
  Assets: {Id: 3a54b880-2b9d-486b-9403-dc2e52d36d65}
  Posts: [{Id: 3}]
BlogAssets {Id: 3a54b880-2b9d-486b-9403-dc2e52d36d65} Unchanged
  Id: '3a54b880-2b9d-486b-9403-dc2e52d36d65' PK FK
  Banner: <null>
  Blog: {Id: 2}
BlogAssets {Id: ed727978-1ffe-4709-baee-73913e8e44a0} Unchanged
  Id: 'ed727978-1ffe-4709-baee-73913e8e44a0' PK FK
  Banner: <null>
  Blog: {Id: 1}
Post {Id: -2147482643} Added
  Id: -2147482643 PK Temporary
  BlogId: 1 FK
  Content: '.NET 5.0 was released recently and has come with many new fe...'
  Title: 'What's next for System.Text.Json?'
  Blog: {Id: 1}
  Tags: []
Post {Id: 1} Unchanged
  Id: 1 PK
  BlogId: 1 FK
  Content: 'Announcing the release of EF Core 5.0, a full featured cross...'
  Title: 'Announcing the Release of EF Core 5.0'
  Blog: {Id: 1}
  Tags: [{Id: 1}, {Id: 3}]
Post {Id: 2} Unchanged
  Id: 2 PK
  BlogId: 1 FK
  Content: 'F# 5 is the latest version of F#, the functional programming...'
  Title: 'Announcing F# 5'
  Blog: {Id: 1}
  Tags: [{Id: 1}]
Post {Id: 3} Unchanged
  Id: 3 PK
  BlogId: 2 FK
  Content: 'If you are focused on squeezing out the last bits of perform...'
  Title: 'Disassembly improvements for optimized managed debugging'
  Blog: {Id: 2}
  Tags: [{Id: 2}]
Post {Id: 4} Deleted
  Id: 4 PK
  BlogId: 2 FK
  Content: 'Examine when database queries were executed and measure how ...'
  Title: 'Database Profiling with Visual Studio'
  Blog: <null>
  Tags: [{Id: 2}]
PostTag (Dictionary<string, object>) {PostsId: 1, TagsId: 1} Unchanged
  PostsId: 1 PK FK
  TagsId: 1 PK FK
PostTag (Dictionary<string, object>) {PostsId: 1, TagsId: 3} Unchanged
  PostsId: 1 PK FK
  TagsId: 3 PK FK
PostTag (Dictionary<string, object>) {PostsId: 2, TagsId: 1} Unchanged
  PostsId: 2 PK FK
  TagsId: 1 PK FK
PostTag (Dictionary<string, object>) {PostsId: 3, TagsId: 2} Unchanged
  PostsId: 3 PK FK
  TagsId: 2 PK FK
PostTag (Dictionary<string, object>) {PostsId: 4, TagsId: 2} Deleted
  PostsId: 4 PK FK
  TagsId: 2 PK FK
Tag {Id: 1} Unchanged
  Id: 1 PK
  Text: '.NET'
  Posts: [{Id: 1}, {Id: 2}]
Tag {Id: 2} Unchanged
  Id: 2 PK
  Text: 'Visual Studio'
  Posts: [{Id: 3}, {Id: 4}]
Tag {Id: 3} Unchanged
  Id: 3 PK
  Text: 'EF Core'
  Posts: [{Id: 1}]

Jede nach verfolgte Entität und Ihr Status werden wie zuvor angezeigt.Each tracked entity and its state is shown as before. In der Long-Ansicht werden jedoch auch Eigenschaften-und Navigations Werte angezeigt.However, the long view also shows property and navigation values.

EigenschaftswerteProperty values

Für jede Eigenschaft wird in der langen Ansicht angezeigt, ob die Eigenschaft Teil eines Primärschlüssels (PK), eines alternativen Schlüssels (AK) oder eines fremd Schlüssels (FK) ist.For each property, the long view shows whether or not the property is part of a primary key (PK), alternate key (AK), or foreign key (FK). Beispiel:For example:

  • Blog.Id ist eine Primärschlüssel Eigenschaft: Id: 1 PKBlog.Id is a primary key property: Id: 1 PK
  • Blog.AssetsId ist eine Alternative Schlüsseleigenschaft: AssetsId: 'ed727978-1ffe-4709-baee-73913e8e44a0' AKBlog.AssetsId is an alternate key property: AssetsId: 'ed727978-1ffe-4709-baee-73913e8e44a0' AK
  • Post.BlogId ist eine Fremdschlüssel Eigenschaft: BlogId: 2 FKPost.BlogId is a foreign key property: BlogId: 2 FK
  • BlogAssets.Id ist sowohl eine Primärschlüssel-als auch eine Fremdschlüssel Eigenschaft: Id: '3a54b880-2b9d-486b-9403-dc2e52d36d65' PK FKBlogAssets.Id is both a primary key and a foreign key property: Id: '3a54b880-2b9d-486b-9403-dc2e52d36d65' PK FK

Eigenschaftswerte, die geändert wurden, werden als solche gekennzeichnet, und der ursprüngliche Wert der-Eigenschaft wird ebenfalls angezeigt.Property values that have been modified are marked as such, and the original value of the property is also shown. Beispiel: Name: '.NET Blog (All new!)' Modified Originally '.NET Blog'.For example, Name: '.NET Blog (All new!)' Modified Originally '.NET Blog'.

Schließlich Added geben Entitäten mit temporären Schlüsselwerten an, dass der Wert temporär ist.Finally, Added entities with temporary key values indicate that the value is temporary. Beispiel: Id: -2147482643 PK Temporary.For example, Id: -2147482643 PK Temporary.

Navigations Werte werden mithilfe der Primärschlüssel Werte der Entitäten angezeigt, auf die der Navigations Verweis verweist.Navigation values are displayed using the primary key values of the entities that the navigations reference. In der obigen Ausgabe bezieht sich z. b. Post 3 auf Blog 2.For example, in the output above, post 3 is related to blog 2. Dies bedeutet, dass die Post.Blog Navigation auf die Blog Instanz mit der ID 2 verweist.This means that the Post.Blog navigation points to the Blog instance with ID 2. Dies wird als dargestellt Blog: {Id: 2} .This is shown as Blog: {Id: 2}.

Dasselbe gilt für Auflistungs Navigationen, mit dem Unterschied, dass es in diesem Fall mehrere Verwandte Entitäten geben kann.The same thing happens for collection navigations, except that in this case there can be multiple related entities. Beispielsweise enthält die Auflistungs Navigation Blog.Posts drei Entitäten mit den Schlüsselwerten 1, 2 und-2147482643.For example, the collection navigation Blog.Posts contains three entities, with key values 1, 2, and -2147482643 respectively. Dies wird als dargestellt [{Id: 1}, {Id: 2}, {Id: -2147482643}] .This is shown as [{Id: 1}, {Id: 2}, {Id: -2147482643}].

Protokollierung protokollierenChange tracker logging

Der Change Tracker protokolliert Nachrichten bei, Debug LogLevel Wenn Änderungen an der Eigenschaft oder Navigationerkannt werden.The change tracker logs messages at the Debug LogLevel whenever it detects property or navigation changes. Wenn z. b. ChangeTracker.DetectChanges() im Code am Anfang dieses Dokuments aufgerufen wird und die Debugprotokollierung aktiviert ist, werden die folgenden Protokolle generiert:For example, when ChangeTracker.DetectChanges() is called in the code at the top of this document and debug logging is enabled, then the following logs are generated:

dbug: 12/30/2020 13:52:44.815 CoreEventId.DetectChangesStarting[10800] (Microsoft.EntityFrameworkCore.ChangeTracking)
      DetectChanges starting for 'BlogsContext'.
dbug: 12/30/2020 13:52:44.818 CoreEventId.PropertyChangeDetected[10802] (Microsoft.EntityFrameworkCore.ChangeTracking)
      The unchanged property 'Blog.Name' was detected as changed from '.NET Blog' to '.NET Blog (All new!)' and will be marked as modified for entity with key '{Id: 1}'.
dbug: 12/30/2020 13:52:44.820 CoreEventId.StateChanged[10807] (Microsoft.EntityFrameworkCore.ChangeTracking)
      The 'Blog' entity with key '{Id: 1}' tracked by 'BlogsContext' changed state from 'Unchanged' to 'Modified'.
dbug: 12/30/2020 13:52:44.821 CoreEventId.CollectionChangeDetected[10804] (Microsoft.EntityFrameworkCore.ChangeTracking)
      1 entities were added and 0 entities were removed from navigation 'Blog.Posts' on entity with key '{Id: 1}'.
dbug: 12/30/2020 13:52:44.822 CoreEventId.ValueGenerated[10808] (Microsoft.EntityFrameworkCore.ChangeTracking)
      'BlogsContext' generated temporary value '-2147482638' for the property 'Id.Post'.
dbug: 12/30/2020 13:52:44.822 CoreEventId.StartedTracking[10806] (Microsoft.EntityFrameworkCore.ChangeTracking)
      Context 'BlogsContext' started tracking 'Post' entity with key '{Id: -2147482638}'.
dbug: 12/30/2020 13:52:44.827 CoreEventId.CollectionChangeDetected[10804] (Microsoft.EntityFrameworkCore.ChangeTracking)
      0 entities were added and 1 entities were removed from navigation 'Blog.Posts' on entity with key '{Id: 2}'.
dbug: 12/30/2020 13:52:44.827 CoreEventId.StateChanged[10807] (Microsoft.EntityFrameworkCore.ChangeTracking)
      The 'Post' entity with key '{Id: 4}' tracked by 'BlogsContext' changed state from 'Unchanged' to 'Modified'.
dbug: 12/30/2020 13:52:44.829 CoreEventId.CascadeDeleteOrphan[10003] (Microsoft.EntityFrameworkCore.Update)
      An entity of type 'Post' with key '{Id: 4}' changed to 'Deleted' state due to severed required relationship to its parent entity of type 'Blog'.
dbug: 12/30/2020 13:52:44.829 CoreEventId.StateChanged[10807] (Microsoft.EntityFrameworkCore.ChangeTracking)
      The 'Post' entity with key '{Id: 4}' tracked by 'BlogsContext' changed state from 'Modified' to 'Deleted'.
dbug: 12/30/2020 13:52:44.829 CoreEventId.CollectionChangeDetected[10804] (Microsoft.EntityFrameworkCore.ChangeTracking)
      0 entities were added and 1 entities were removed from navigation 'Blog.Posts' on entity with key '{Id: 2}'.
dbug: 12/30/2020 13:52:44.831 CoreEventId.CascadeDelete[10002] (Microsoft.EntityFrameworkCore.Update)
      A cascade state change of an entity of type 'PostTag' with key '{PostsId: 4, TagsId: 2}' to 'Deleted' occurred due to the deletion of its parent entity of type 'Post' with key '{Id: 4}'.
dbug: 12/30/2020 13:52:44.831 CoreEventId.StateChanged[10807] (Microsoft.EntityFrameworkCore.ChangeTracking)
      The 'PostTag' entity with key '{PostsId: 4, TagsId: 2}' tracked by 'BlogsContext' changed state from 'Unchanged' to 'Deleted'.
dbug: 12/30/2020 13:52:44.831 CoreEventId.DetectChangesCompleted[10801] (Microsoft.EntityFrameworkCore.ChangeTracking)
      DetectChanges completed for 'BlogsContext'.

In der folgenden Tabelle werden die Protokollierungs Meldungen der Änderungs Protokollierung zusammengefasstThe following table summaries the change tracker logging messages:

Ereignis-IDEvent ID BESCHREIBUNGDescription
CoreEventId.DetectChangesStarting DetectChanges() wird gestartetDetectChanges() is starting
CoreEventId.DetectChangesCompleted DetectChanges() wurde abgeschlossen.DetectChanges() has completed
CoreEventId.PropertyChangeDetected Ein normaler Eigenschafts Wert wurde geändert.A normal property value has changed
CoreEventId.ForeignKeyChangeDetected Ein Fremdschlüssel-Eigenschafts Wert wurde geändert.A foreign key property value has changed
CoreEventId.CollectionChangeDetected In einer Auflistungs Navigation ohne überspringen wurden Verwandte Entitäten hinzugefügt oder entfernt.A non-skip collection navigation has had related entities added or removed.
CoreEventId.ReferenceChangeDetected Eine Verweis Navigation wurde geändert, um auf eine andere Entität zu zeigen, oder auf NULL festgelegt.A reference navigation has been changed to point to another entity, or set to null
CoreEventId.StartedTracking EF Core die Nachverfolgung einer Entität gestartetEF Core started tracking an entity
CoreEventId.StateChanged Der einer EntityState Entität hat sich geändert.The EntityState of an entity has changed
CoreEventId.ValueGenerated Für eine Eigenschaft wurde ein Wert generiert.A value was generated for a property
CoreEventId.SkipCollectionChangeDetected In einer Navigation zum Überspringen der Auflistung wurden Verwandte Entitäten hinzugefügt oder entferntA skip collection navigation has had related entities added or removed

Die Model-KomponenteThe model

Das Modell, das für die obigen Beispiele verwendet wird, enthält die folgenden Entitäts Typen:The model used for the examples above contains the following entity types:

public class Blog
{
    public int Id { get; set; } // Primary key
    public Guid AssetsId { get; set; } // Alternate key
    public string Name { get; set; }

    public IList<Post> Posts { get; } = new List<Post>(); // Collection navigation
    public BlogAssets Assets { get; set; } // Reference navigation
}

public class BlogAssets
{
    public Guid Id { get; set; } // Primary key and foreign key
    public byte[] Banner { get; set; }

    public Blog Blog { get; set; } // Reference navigation
}

public class Post
{
    public int Id { get; set; } // Primary key
    public string Title { get; set; }
    public string Content { get; set; }

    public int BlogId { get; set; } // Foreign key
    public Blog Blog { get; set; } // Reference navigation

    public IList<Tag> Tags { get; } = new List<Tag>(); // Skip collection navigation
}

public class Tag
{
    public int Id { get; set; } // Primary key
    public string Text { get; set; }

    public IList<Post> Posts { get; } = new List<Post>(); // Skip collection navigation
}

Das Modell wird größtenteils gemäß der Konvention konfiguriert, mit nur wenigen Zeilen in "onmodelcreating":The model is mostly configured by convention, with just a few lines in OnModelCreating:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder
        .Entity<Blog>()
        .Property(e => e.AssetsId)
        .ValueGeneratedOnAdd();

    modelBuilder
        .Entity<BlogAssets>()
        .HasOne(e => e.Blog)
        .WithOne(e => e.Assets)
        .HasForeignKey<BlogAssets>(e => e.Id)
        .HasPrincipalKey<Blog>(e => e.AssetsId);
}