W jednym z poprzednich wpisów (EF Core - UPDATE) w sekcji Zrozumieć EntityState pierwszy raz mieliśmy styczność z biblioteką Microsoft.EntityFrameworkCore.ChangeTracking. Pozwala ona na śledzenie stanu każdej encji w obrębie tego samego kontekstu. Dzięki niej sprawdziliśmy zmiany EntityState w zależności od defincji (lub braku) identyfikatora danej encji.
Klasa ChangeTracker rozpoczyna śledzenie wszystkich jednostek, które zostały pobrane przy użyciu DbContext (scenariusz połączony) i nie są modyfikowane poza tym kontekstem (scenariusz rozłączony). Entity Framework Core śledzi wszystkie zmiany jednostek i ich wartości – dzięki temu jest w stanie kompilować i wykonywać odpowiednie instrukcje DML (zbiór instrukcji pozwalających na przetwarzanie danych, tj. INSERT, UPDATE, DELETE oraz MERGE - kombinacja trzech wspomnianych instrukcji) na podpiętej bazie danych.
Stan encji reprezentowany jest przez typ wyliczeniowy Microsoft.EntityFrameworkCore.EntityState, który przyjmuje jedną z poniższych wartości:
Added;
Modified;
Deleted;
Unchanged;
Detached;
Wykorzystując kod z poprzedniego wpisu sprawdzimy automatyczne zmiany zachodzące na danej encji na podstawie różnych operacji:
Stan od którego zaczynamy to: Unchanged. Dane pobrane za pomocą nieprzetworzonego zapytania SQL lub LINQ-to-Entities przyjmą stan 'niezmieniony':
// Wymagana paczka: Microsoft.EntityFrameworkCore.ChangeTracking
private static void CheckEntityState(IEnumerable<EntityEntry> records)
{
foreach (var row in records)
{
Console.WriteLine($"Encja: {row.Entity.GetType().Name}, EntityState: {row.State}");
}
}
static void Main(string[] args)
{
using(var context = new ApplicationDbContext())
{
// pobranie pierwszej osoby z tabeli
var person = context.Person.First();
CheckEntityState(context.ChangeTracker.Entries());
}
}
Stan: Added
Wszystkie nowe encje bez wartości klucza dodane w danym kontekście przy użyciu metody Add lub Update (ten przykład analizowaliśmy dwa wpisy temu) zostaną oznaczone stanem Added:
using(var context = new ApplicationDbContext())
{
var person = new Person() { FullName = "Paweł" };
context.Add(person); // Zmiana entity state na Added
CheckEntityState(context.ChangeTracker.Entries());
}
Stan: Modified
Jeżeli wartość encji zostanie zmieniona w obrębie DbContext dojdzie do automatycznej zmiany stanu na Modified:
using(var context = new ApplicationDbContext())
{
var person = context.Person.First();
person.FullName = "Modified"; // Zmiana entity state na Modified
CheckEntityState(context.ChangeTracker.Entries());
}
Stan: Deleted
Usunięcie jednostki z kontekstu przy użyciu metody Remove spowoduje automatyczną zmianę stanu na Deleted:
using(var context = new ApplicationDbContext())
{
var person = context.Person.First();
context.Person.Remove(person); // Zmiana entity state na Deleted
CheckEntityState(context.ChangeTracker.Entries());
}
Stan: Detached
Jednostki utworzone lub pobrane poza bieżącym kontekstem będą oznaczone jako: Detached (odłączone) – temu zagadnieniu poświęciłem kilka osobnych wpisów omawiając ten scenariusz w zależności od różnych instrukcji. Z perspektywy tego przykładu najważniejsza jest informacja, że encje takie (zmiany) nie są śledzone przez istniejący DbContext:
// encja utworzona poza kontekstem
var person = new Person() { FullName = "Deteched" };
using(var context = new ApplicationDbContext())
{
// Stan: detached
Console.WriteLine(context.Entry(person).State);
// Dołączenie jednostki i rozpoczęcie śledzenia
context.Add<Person>(person);
CheckEntityState(context.ChangeTracker.Entries());
}