Ä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:
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
oderDeleted
.This will be one ofUnchanged
,Added
,Modified
, orDeleted
. - 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 PK
Blog.Id
is a primary key property:Id: 1 PK
Blog.AssetsId
ist eine Alternative Schlüsseleigenschaft:AssetsId: 'ed727978-1ffe-4709-baee-73913e8e44a0' AK
Blog.AssetsId
is an alternate key property:AssetsId: 'ed727978-1ffe-4709-baee-73913e8e44a0' AK
Post.BlogId
ist eine Fremdschlüssel Eigenschaft:BlogId: 2 FK
Post.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 FK
BlogAssets.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 WerteNavigation values
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);
}