Jegyzet
Az oldalhoz való hozzáférés engedélyezést igényel. Próbálhatod be jelentkezni vagy könyvtárat váltani.
Az oldalhoz való hozzáférés engedélyezést igényel. Megpróbálhatod a könyvtár váltását.
Az Entity Framework Core (EF Core) változáskövetője kétféle kimenetet hoz létre a hibakereséshez:
- Az ChangeTracker.DebugView egy emberi olvasási formátumot biztosít az összes nyomon követett elemhez.
- Hibakeresési szintű naplóüzenetek akkor jönnek létre, amikor a változáskövető észleli az állapotot, és kijavítja a kapcsolatokat
Jótanács
Ez a dokumentum feltételezi, hogy az entitásállapotok és az EF Core-változáskövetés alapjai érthetőek. Ezekről a témakörökről további információt az EF Core változáskövetési funkciójában talál.
Jótanács
A mintakód GitHubról való letöltésével futtathatja és hibakeresést végezhet a dokumentum összes kódjában.
Változáskövető hibakeresési nézet
A változáskövető hibakeresési nézet az IDE hibakeresőjében érhető el. Például a Visual Studióval:
Közvetlenül a kódból is elérhető, például a hibakeresési nézet elküldéséhez a konzolra:
Console.WriteLine(context.ChangeTracker.DebugView.ShortView);
A hibakeresési nézet rövid és hosszú formátumú. A rövid űrlap a nyomon követett entitásokat, azok állapotát és kulcsértékeit jeleníti meg. A hosszú űrlap az összes tulajdonságot és navigációs értéket és állapotot is tartalmazza.
A rövid nézet
Tekintsünk meg egy hibakeresési nézetet a dokumentum végén látható modell használatával. Először is nyomon követünk néhány entitást, és különböző állapotba helyezzük őket, csak azért, hogy jó változáskövetési adatokat tekintsünk meg:
using var context = new BlogsContext();
var blogs = await context.Blogs
.Include(e => e.Posts).ThenInclude(e => e.Tags)
.Include(e => e.Assets)
.ToListAsync();
// 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();
Az itt látható rövid nézet nyomtatása a következő kimenetet eredményezi:
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
Megjegyzés:
- Minden nyomon követett entitás az elsődleges kulcs (PK) értékével van felsorolva. Például:
Blog {Id: 1}. - Ha az entitás megosztott típusú entitástípus, akkor a CLR-típus is megjelenik. Például:
PostTag (Dictionary<string, object>). - Következőnek a EntityState látható. Ez lesz az egyik
Unchanged,Added,ModifiedvagyDeleted. - Az alternatív kulcsok (AK-k) értékei a következőkben láthatók. Például:
AK {AssetsId: ed727978-1ffe-4709-baee-73913e8e44a0}. - Végül megjelennek az idegen kulcsok (FK-k) értékei. Például:
FK {PostsId: 4} FK {TagsId: 2}.
A hosszú nézet
A hosszú nézet a rövid nézethez hasonlóan küldhető el a konzolra:
Console.WriteLine(context.ChangeTracker.DebugView.LongView);
A fenti rövid nézettel megegyező állapot kimenete a következő:
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}]
Minden nyomon követett entitás és állapota a korábbiakhoz hasonlóan jelenik meg. A hosszú nézet azonban a tulajdonság- és navigációs értékeket is megjeleníti.
Tulajdonságértékek
Minden tulajdonság esetében a hosszú nézet azt mutatja, hogy a tulajdonság egy elsődleges kulcs (PK), alternatív kulcs (AK) vagy idegen kulcs (FK) része-e. Például:
-
Blog.Idelsődleges kulcstulajdonság:Id: 1 PK -
Blog.AssetsIdegy másik kulcstulajdonság:AssetsId: 'ed727978-1ffe-4709-baee-73913e8e44a0' AK -
Post.BlogIdidegen kulcs tulajdonság:BlogId: 2 FK -
BlogAssets.Idegyszerre elsődleges kulcs és külső kulcs tulajdonság:Id: '3a54b880-2b9d-486b-9403-dc2e52d36d65' PK FK
A módosított tulajdonságértékek ilyenként vannak megjelölve, és a tulajdonság eredeti értéke is megjelenik. Például: Name: '.NET Blog (All new!)' Modified Originally '.NET Blog'.
Végül az Added ideiglenes kulcsértékekkel rendelkező entitások azt jelzik, hogy az érték ideiglenes. Például: Id: -2147482643 PK Temporary.
Navigációs értékek
A navigációs értékek azon entitások elsődleges kulcsértékeivel jelennek meg, amelyekre a navigáció hivatkozik. A fenti kimenetben például a 3. bejegyzés a 2. bloghoz kapcsolódik. Ez azt jelenti, hogy a Post.Blog navigáció a Blog példányra mutat azonosítóval 2. Ez a következőképpen jelenik meg Blog: {Id: 2}.
Ugyanez történik a gyűjtemény-navigációk esetében is, kivéve, hogy ebben az esetben több kapcsolódó entitás is lehet. A gyűjteménynavigáció Blog.Posts például három entitást tartalmaz, amelyek 1, 2 és -2147482643 fő értékeket tartalmaznak. Ez a következőképpen jelenik meg [{Id: 1}, {Id: 2}, {Id: -2147482643}].
Változáskövetési naplózás
A változáskövető naplózza az üzeneteket, DebugLogLevel amikor tulajdonság- vagy navigációs változásokat észlel. Ha például ChangeTracker.DetectChanges() a rendszer meghívja a dokumentum tetején található kódban, és engedélyezve van a hibakeresési naplózás, akkor a következő naplók jönnek létre:
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'.
Az alábbi táblázat összefoglalja a változáskövető naplózási üzeneteit:
| Eseményazonosító | Leírás |
|---|---|
| CoreEventId.DetectChangesStarting | DetectChanges() indul |
| CoreEventId.DetectChangesCompleted | DetectChanges() befejeződött |
| CoreEventId.PropertyChangeDetected | Módosult egy normál tulajdonságérték |
| CoreEventId.ForeignKeyChangeDetected | Módosult egy idegenkulcs-tulajdonság értéke |
| CoreEventId.CollectionChangeDetected | A teljes gyűjtemény navigációjához kapcsolódó entitások lettek hozzáadva vagy eltávolítva. |
| CoreEventId.ReferenceChangeDetected | A hivatkozásnavigáció egy másik entitásra mutat, vagy null értékre van állítva |
| CoreEventId.StartedTracking | Az EF Core elkezdett nyomon követni egy entitást |
| CoreEventId.StateChanged | Egy EntityState entitás módosult |
| CoreEventId.ValueGenerated | Érték lett létrehozva egy tulajdonsághoz |
| CoreEventId.SkipCollectionChangeDetected | A kihagyott gyűjtemény navigációs sávjához kapcsolódó entitások lettek hozzáadva vagy eltávolítva |
A modell
A fenti példákhoz használt modell a következő entitástípusokat tartalmazza:
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
}
A modell többnyire konvenció szerint van konfigurálva, mindössze néhány sor az OnModelCreatingben:
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);
}