Change Tracker
Selamlar, Bu makalede Entity Framework Core Change Tracker yapısının nasıl çalıştığından bahsediyor olacağız. Konuya basit seviyede bir örnek ile giriş yapalım ve örnek üzerinden detaylandırmaya çalışalım.
public async Task<IActionResult> GetProduct(int id = 50)
{
using (var context = new NorthwindContext())
{
var product = await context.Products.FirstOrDefaultAsync(p => p.ProductId == id);
product.ProductName = "Pringles Paprika";
await context.SaveChangesAsync();
return Ok(product);
}
}Örneği inceleyecek olursak, basit bir update işlemi gerçekleştirdik, dikkat ederseniz kod içersinde UPDATE ile ilgili herhangi bir method çağırımı bulunmamaktadır. Tek yaptığımız değişiklikten sonra SaveChangesAsync(); metodunu çağırmak. Peki Entity Framework Core nesne üzerindeki bu değişikliği nasıl algıladı? Yapılan değişikliğin update işlemi olduğuna ve update sorgusu generate etmesi gerektiğine nasıl karar verdi? Tüm bu soruların cevabı ise Change Tracker yapısıdır.
Change Tracker Nedir?
Entity Framework Core içerisinde bulunan bir takip mekanizmasıdır. Context üzerinden nesneler üzerinden yapılan tüm değişiklikler bu yapı sayesinde takip edilir. Bu takip neticesinde nesne üzerinde yapılan değişikliklerden context haberdar edilir.
using (var context = new NorthwindContext())
{
var tracker = context.ChangeTracker;
}State Türleri
- Detached: Takip yapılmadığı anlamına gelir.
- Modified: Update
- Added: Insert
- Unchanged: Nesne üzerinde değişiklik olmadığını ifade eder.
- Deleted: Delete
Change Tracker DetectChanges
Context üzerinden bir nesne değişikliğe uğradığında(INSERT,UPDATE,DELETE) arka planda tetiklenen methoddur, context bu method sayesinde uyarılmaktadır. SaveChanges(); metodu çağırıldığında da arka planda bu method tetiklemektedir.
using (var context = new NorthwindContext())
{
var tracker = context.ChangeTracker;
tracker.DetectChanges();
}AutoDetectChangesEnabled
Change Tracker içerisinde bulunan bu property, context üzerinde bir takibin yapılıp yapılmayacağını belirlemek için kullanılır. Varsayılan olarak “True” set edilmiştir. Takibi kopartmak istersek değerini “False” olarak set etmek yeterli olacaktır. O dakikadan sonra context üzerinde takip yapılmayacak, nesneler üzerinde değişiklik olsa dahi nesne durumu hep UnChanged olarak kalacaktır.
using (var context = new NorthwindContext())
{
var tracker = context.ChangeTracker;
tracker.AutoDetectChangesEnabled = false;
}Change Tracker HasChanges
Change Tracker içerisinden gelen bu method ile nesne üzerinde bir değişiklik olup olmadığını kontrol edebiliriz. Değişiklik var ise “True” yok ise “False” dönecektir.
using (var context = new NorthwindContext())
{
var tracker = context.ChangeTracker;
var product = await context.Products.FirstOrDefaultAsync(p=> p.ProductId==id);
if (product == null) { return NotFound(new {message="Record Not Found"});}
else
{
var availableState = context.Entry(product).State;
product.ProductName = "Diverso DV1118";
var checkStatusChange = tracker.HasChanges();
var newState=context.Entry(product).State;
}
}Entries
Tekil veriler ile değil koleksiyonlar ile çalışıyorsak, koleksiyon içersindeki nesneleri elde etmek için bu methodu kullanabiliriz. IEnumerable türünde dönüş yapan bu method her bir nesneyi EntityEntry türünde dönecektir. Bir döngü yardımı ile her bir nesneyi gezip, nesneler üzerinde işlemler yapabiliriz.
using (var context = new NorthwindContext())
{
var tracker = context.ChangeTracker;
var products = await context.Products.ToListAsync();
var entries=tracker.Entries();
foreach (EntityEntry entry in entries)
{
var product = entry.Entity as Product;
}
}Entry ile OriginalValues,CurrentValues Değerlerini Elde Etmek
Bu aşamaya kadar Change Tracker üzerinden gelen method ve propertyleri inceledik. Entries metodu koleksiyonlar ile çalışmamıza imkan sağlarken context içersinden gelen Entry(); metodu ise tekil nesneler üzerinde çalışmamıza imkan sağlamaktadır.
using (var context = new NorthwindContext())
{
var product = await context.Products.FirstOrDefaultAsync(p => p.ProductId == id);
var entry = context.Entry(product);
var originalValue= entry.OriginalValues.GetValue<string>("ProductName");
product.ProductName = "Outliers";
var newValue= entry.CurrentValues.GetValue<string>("ProductName");
}AsNoTracking ile Sorgu Bazında Takibin Kopartılması
Change Tracker mekanizmasının devre dışı bırakılabildiğinden bahsetmiştik. Burada dikkat edilmesi gereken ise yerinde ve ihtiyaç dahilinde bu işlemin yapılmasıdır. Sorgu optimizasyonundan avantaj sağlamasının yanında çetşitli maliyetlerde ortaya çıkarmaktadır. Elde edilecek nesne yada nesneler üzerinde bir değişiklik olmayacağı garanti ise takinin koparılması mantıklı bir kullanım olacaktır.
Get Evren Aktas’s stories in your inbox
Join Medium for free to get updates from this writer.
Takibin koparıldığı ama nesne üzerinde değişiklik olduğu senaryoda ise geliştirici bu değişiklikleri algılanabilmesi için gerekli çalışmayı kendisi yapması gerekecektir. Entity sayısı ve uygulamanın veri kaynağı ile olan ilişkisi arttıkça yönetilmesi zor bir durum haline gelen bu kullanımda, takibin elde edilen verinin
kullanım amacına göre koparılmasına yada koparılmamasına karar vermek gerekmektedir. Bu noktada sorgu bazında takibin koparılması için AsNoTracking(); metodunu kullanabiliriz.
using (var context = new NorthwindContext())
{
var product = await context.Products.AsNoTracking().FirstOrDefaultAsync(p => p.ProductId == id);
product.ProductName = $"{id}";
var state = context.Entry(product).State;
}Görseli inceleyecek olursak, AsNoTracking(); metodu ile sorgu bazında takibin kopartılmasının ardından nesne üzerinde değişiklik yapılmış olsa dahi, nesnenin durumu Detached olarak kalmaktadır. Buda context üzerinde takibin yapılmadığı anlamına gelmektedir.
Beni Linkedin Github Twitter üzerinden takip edebilirsiniz. Bir başka makalede görüşmek üzere. Hoşçakalın :)








