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.
Minden DbContext példány nyomon követi az entitások módosításait. Ezek a nyomon követett entitások viszont az adatbázis változásait hajtják végre, amikor SaveChanges meghívják őket.
Ez a dokumentum áttekintést nyújt az Entity Framework Core (EF Core) változáskövetéséről, valamint arról, hogyan kapcsolódik a lekérdezésekhez és frissítésekhez.
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.
Entitások nyomon követése
Az entitáspéldányok a következő esetekben lesznek nyomon követve:
- Az adatbázison végrehajtott lekérdezésből visszaadva
- Explicit módon csatolva a DbContexthez
Add,Attach,Updatevagy hasonló módszerekkel - Új entitásként észlelve, amely a meglévő nyomon követett entitásokhoz csatlakozik
Az entitáspéldányok a továbbiakban nem lesznek nyomon követve, ha:
- A DbContext felszabadításra került
- A változáskövető törlődik
- Az entitások explicit módon vannak leválasztva
A DbContext úgy lett kialakítva, hogy egy rövid életű munkaegységet képviseljen a DbContext inicializálásában és konfigurálásában leírtak szerint. Ez azt jelenti, hogy az entitások nyomon követésének leállításához a DbContext letiltása a szokásos módszer . Más szóval a DbContext élettartamának a következőnek kell lennie:
- A DbContext-példány létrehozása
- Egyes entitások nyomon követése
- Az entitások néhány módosítása
- A SaveChanges hívása az adatbázis frissítéséhez
- A DbContext-példány elvetése
Jótanács
Ennek a megközelítésnek a használatakor nem szükséges törölni a változáskövetőt, vagy explicit módon leválasztani az entitáspéldányokat. Ha azonban le kell választania az entitásokat, akkor a hívás ChangeTracker.Clear hatékonyabb, mint az entitások egyenkénti leválasztása.
Entitásállapotok
Minden entitás egy adott EntityState:
-
Detachedentitásokat a rendszer nem követi nyomon.DbContext -
Addedaz entitások újak, és még nem lettek beszúrva az adatbázisba. Ez azt jelenti, hogy a rendszer beszúrja őket, amikor SaveChanges meghívják őket. -
Unchangedaz entitások nem módosultak, mióta lekérdezték őket az adatbázisból. A lekérdezésekből visszaadott összes entitás kezdetben ebben az állapotban van. -
Modifiedentitások módosultak, mióta lekérdezték őket az adatbázisból. Ez azt jelenti, hogy a SaveChanges meghívásakor frissülnek. -
Deletedentitások léteznek az adatbázisban, de a Rendszer a SaveChanges meghívásakor törli őket.
Az EF Core a tulajdonságok szintjén követi nyomon a változásokat. Ha például csak egyetlen tulajdonságértéket módosít, akkor az adatbázis frissítése csak ezt az értéket módosítja. A tulajdonságok azonban csak akkor jelölhetők módosítottként, ha maga az entitás módosított állapotban van. (Másik szempontból a Módosított állapot azt jelenti, hogy legalább egy tulajdonságérték módosult.)
Az alábbi táblázat a különböző állapotokat foglalja össze:
| Entitás állapota | A DbContext által követve | Létezik az adatbázisban | Módosított tulajdonságok | Művelet a változások mentésén |
|---|---|---|---|---|
Detached |
Nem | - | - | - |
Added |
Igen | Nem | - | Beilleszt |
Unchanged |
Igen | Igen | Nem | - |
Modified |
Igen | Igen | Igen | Frissítés |
Deleted |
Igen | Igen | - | Törlés |
Megjegyzés:
Ez a szöveg a relációs adatbázis kifejezéseket használja az egyértelműség érdekében. A NoSQL-adatbázisok általában támogatják a hasonló műveleteket, de valószínűleg más néven. További információért tekintse meg az adatbázis-szolgáltató dokumentációját.
Lekérdezésekből származó nyomkövetés
Az EF Core változáskövetése akkor működik a legjobban, ha ugyanazt DbContext a példányt használják az entitások lekérdezésére, és hívással SaveChangesfrissítik őket. Ennek az az oka, hogy az EF Core automatikusan nyomon követi a lekérdezett entitások állapotát, majd észleli az entitások módosításait a SaveChanges meghívásakor.
Ez a megközelítés számos előnnyel rendelkezik az entitáspéldányok explicit nyomon követésével szemben:
- Ez egyszerű. Az entitásállapotokat ritkán kell explicit módon manipulálni – az EF Core gondoskodik az állapotváltozásról.
- A frissítések csak azokra az értékekre korlátozódnak, amelyek ténylegesen megváltoztak.
- Az árnyéktulajdonságok értékei szükség szerint megmaradnak és használhatók. Ez különösen akkor fontos, ha az idegen kulcsok árnyékállapotban vannak tárolva.
- A tulajdonságok eredeti értékei automatikusan megmaradnak, és a hatékony frissítésekhez használhatók.
Egyszerű lekérdezés és frissítés
Vegyük például egy egyszerű blog-/bejegyzésmodellt:
public class Blog
{
public int Id { get; set; }
public string Name { get; set; }
public IList<Post> Posts { get; } = new List<Post>();
}
public class Post
{
public int Id { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public int? BlogId { get; set; }
public Blog Blog { get; set; }
}
Ezzel a modellel lekérdezhetjük a blogokat és a bejegyzéseket, majd frissíthetjük az adatbázist:
using var context = new BlogsContext();
var blog = await context.Blogs.Include(e => e.Posts).FirstAsync(e => e.Name == ".NET Blog");
blog.Name = ".NET Blog (Updated!)";
await foreach (var post in blog.Posts.AsQueryable().Where(e => !e.Title.Contains("5.0")).AsAsyncEnumerable())
{
post.Title = post.Title.Replace("5", "5.0");
}
await context.SaveChangesAsync();
A SaveChanges hívása az alábbi adatbázis-frissítéseket eredményezi, példaadatbázisként használva az SQLite-t:
-- Executed DbCommand (0ms) [Parameters=[@p1='1' (DbType = String), @p0='.NET Blog (Updated!)' (Size = 20)], CommandType='Text', CommandTimeout='30']
UPDATE "Blogs" SET "Name" = @p0
WHERE "Id" = @p1;
SELECT changes();
-- Executed DbCommand (0ms) [Parameters=[@p1='2' (DbType = String), @p0='Announcing F# 5.0' (Size = 17)], CommandType='Text', CommandTimeout='30']
UPDATE "Posts" SET "Title" = @p0
WHERE "Id" = @p1;
SELECT changes();
A változáskövető hibakeresési nézet nagyszerű módja annak, hogy megjelenítse a nyomon követett entitásokat és azok állapotát. Például szúrja be a következő kódot a fenti mintába a SaveChanges meghívása előtt:
context.ChangeTracker.DetectChanges();
Console.WriteLine(context.ChangeTracker.DebugView.LongView);
A következő kimenetet hozza létre:
Blog {Id: 1} Modified
Id: 1 PK
Name: '.NET Blog (Updated!)' Modified Originally '.NET Blog'
Posts: [{Id: 1}, {Id: 2}, {Id: 3}]
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}
Post {Id: 2} Modified
Id: 2 PK
BlogId: 1 FK
Content: 'F# 5 is the latest version of F#, the functional programming...'
Title: 'Announcing F# 5.0' Modified Originally 'Announcing F# 5'
Blog: {Id: 1}
Figyelje meg a következőt:
- A
Blog.Nametulajdonság módosultként (Name: '.NET Blog (Updated!)' Modified Originally '.NET Blog') van megjelölve, és ez azt eredményezi, hogy a blog állapotbanModifiedvan. - A második bejegyzés
Post.Titletulajdonsága módosítottként (Title: 'Announcing F# 5.0' Modified Originally 'Announcing F# 5') van megjelölve, és ez azt eredményezi, hogy ez a bejegyzés aModifiedállapotban van. - A 2. utáni többi tulajdonságérték nem módosult, ezért nem módosultként van megjelölve. Ezért ezek az értékek nem szerepelnek az adatbázis frissítésében.
- A másik bejegyzés semmilyen módon nem módosult. Ezért van még mindig állapotban
Unchanged, és nem szerepel az adatbázis frissítésében.
Lekérdezés, majd beszúrás, frissítés és törlés
Az előző példához hasonló frissítések kombinálhatók beszúrásokkal és törlésekkel ugyanabban a munkaegységben. Például:
using var context = new BlogsContext();
var blog = await context.Blogs.Include(e => e.Posts).FirstAsync(e => e.Name == ".NET Blog");
// Modify property values
blog.Name = ".NET Blog (Updated!)";
// Insert a new Post
blog.Posts.Add(
new Post
{
Title = "What’s next for System.Text.Json?", Content = ".NET 5.0 was released recently and has come with many..."
});
// Mark an existing Post as Deleted
var postToDelete = blog.Posts.Single(e => e.Title == "Announcing F# 5");
context.Remove(postToDelete);
context.ChangeTracker.DetectChanges();
Console.WriteLine(context.ChangeTracker.DebugView.LongView);
await context.SaveChangesAsync();
Ebben a példában:
- A blogot és a kapcsolódó bejegyzéseket lekérdezik az adatbázisból, és nyomon követik
- A
Blog.Nametulajdonság megváltozott - Új bejegyzést adunk hozzá a blog meglévő bejegyzéseinek gyűjteményéhez
- A rendszer meghív egy meglévő bejegyzést törlésre DbContext.Remove
A SaveChanges hívása előtt újra megtekinti a változáskövető hibakeresési nézetet , és megmutatja, hogy az EF Core hogyan követi nyomon ezeket a módosításokat:
Blog {Id: 1} Modified
Id: 1 PK
Name: '.NET Blog (Updated!)' Modified Originally '.NET Blog'
Posts: [{Id: 1}, {Id: 2}, {Id: 3}, {Id: -2147482638}]
Post {Id: -2147482638} Added
Id: -2147482638 PK Temporary
BlogId: 1 FK
Content: '.NET 5.0 was released recently and has come with many...'
Title: 'What's next for System.Text.Json?'
Blog: {Id: 1}
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}
Post {Id: 2} Deleted
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}
Figyelje meg az alábbiakat:
- A blog a következőként
Modifiedvan megjelölve: . Ez létrehoz egy adatbázis-frissítést. - A 2. bejegyzés a következőképpen van megjelölve
Deleted: . Ez létrehoz egy adatbázis-törlést. - Az ideiglenes azonosítóval rendelkező új bejegyzés az 1. bloghoz van társítva, és a következőképpen van megjelölve
Added: . Ez létrehoz egy adatbázis-beszúrást.
Ez a következő adatbázis-parancsokat eredményezi (SQLite használatával) a SaveChanges meghívásakor:
-- Executed DbCommand (0ms) [Parameters=[@p1='1' (DbType = String), @p0='.NET Blog (Updated!)' (Size = 20)], CommandType='Text', CommandTimeout='30']
UPDATE "Blogs" SET "Name" = @p0
WHERE "Id" = @p1;
SELECT changes();
-- Executed DbCommand (0ms) [Parameters=[@p0='2' (DbType = String)], CommandType='Text', CommandTimeout='30']
DELETE FROM "Posts"
WHERE "Id" = @p0;
SELECT changes();
-- Executed DbCommand (0ms) [Parameters=[@p0='1' (DbType = String), @p1='.NET 5.0 was released recently and has come with many...' (Size = 56), @p2='What's next for System.Text.Json?' (Size = 33)], CommandType='Text', CommandTimeout='30']
INSERT INTO "Posts" ("BlogId", "Content", "Title")
VALUES (@p0, @p1, @p2);
SELECT "Id"
FROM "Posts"
WHERE changes() = 1 AND "rowid" = last_insert_rowid();
Az entitások beszúrásával és törlésével kapcsolatos további információkért lásd az Explicitly Tracking Entities című témakört. Lásd a változásészlelés és az értesítések részben további információt arról, hogyan észleli automatikusan az EF Core az ilyen jellegű változásokat.
Jótanács
Hívás ChangeTracker.HasChanges() annak megállapítására, hogy történtek-e olyan módosítások, amelyek miatt a SaveChanges frissíti az adatbázist. Ha a HasChanges hamis értéket ad vissza, akkor a SaveChanges no-oplesz.