Entity Framework Core & Change Tracker API, Tracking vs. No-Tracking Queries, AsNoTracking()

Semih Elitaş
Ada Yazılım
Published in
5 min readMay 18, 2020

Entity Framework Core 2016 yılından itibaren .NET Core platformu için geliştirilen bir ORM (Object Relational Mapping) aracıdır. Bu araç sayesinde bir çok veritabanı işlemimizi daha kolay bir şekilde yapmaktayız. Kendimizin yapması gereken birçok işi veya bizim halletmemiz gereken Create, Update, Delete ve benzeri işlemleri bize hazır olarak sunmakta.

Bu makalede not defterime bir ara uzun uzun notlar aldığım Entity Framework içerisinde bulunan ChangeTracker yapısından ve izlenilebilen/izlenilemeyen sorgu tiplerinden bahsetmek istiyorum.

Entity Framework Core & ChangeTracker İlişkisi

Entity Framework Core içerisindeki DbContext, aynı DbContext instance’ı kullanılarak alınan her bir varlığın durumunu izlemekten sorumlu olanMicrosoft.EntityFrameworkCore.ChangeTracking” namespace içerisinde bulunan ChangeTracker sınıfını içerir.

Bu sınıfın görevi; DbContext kullanılarak alınan bütün objeleri kapsamının (scope) dışına çıkıncaya kadar izlemektir.

Bunun amacı ise Entity Framework’ün tüm entity ve propertyler üzerinde uygulanan tüm değişiklikleri izleyerek, bu değişimleri veri kaynağına doğru bir şekilde yansıtabilmek ve uygun DML (Data Manipulation Language) ifadeleri oluşturabilmektir.

Tabii ki bu izlenme durumunun standart senaryoda yani default olarak yapıldığını belirtmekte fayda var, ikinci kısımda bunun hakkında konuşacağız.

Buna göre bir entity, bu izlenme süresince herhangi bir zamanda aşağıdaki durumlardan birine sahiptir:

Added, Modified, Deleted, Unchanged, Detached

Haydi bu durumların bizlere ne ifade etmeye çalıştığını kod üzerinde görelim!

DbContext & Migrations

Hızlıca bir DbContext oluşturuyorum;

Developer sınıfı:

DbSet’imi tanımladıktan ve database pathingi verdikten sonra migration işlemlerini Package Manager Console üzerinden gerçekleştiriyorum:

PM> add-migration InitialCreate

PM> update-database

Migration işlemlerinden sonra artık veritabanımız kullanıma hazır. Haydi bir kaç örnek ile beraber nesnelerin durumlarını inceleyelim.

Unchanged State

Nesne, contexte eklendiğinden beri veya SaveChanges() metodunun son çağırılışından itibaren hiçbir değişikliğe uğramamışsa Unchanged durumunu alır. Doğrudan SQL sorgusu veya LINQ-to-Entities sorguları kullanılarak alınan tüm nesnelerde ayrıca bu durumdadır.

Örnek:

Veritabanı içerisinde veri bulunmaktadır*

Yukarıdaki örnekte görüldüğü gibi FirstOrDefault metoduyla Developers tablosundaki ilk ögeyi almak istedik. Bu işlemden sonra ChangeTracker aracılığıyla işlemin hangi durumda olduğunu sorguluyoruz ve Unchanged olduğunu görüyoruz. Çünkü biz bir okuma işlemi yaptık ve bu veritabanında herhangi bir değişime sebep olmayacak. Dolayısıyla bu okuma işleminden sonra SaveChanges() metodunu çağırmamız biraz anlamsız olacaktır.

Added State

Adından da anlaşılacağı gibi yeni bir nesne ekleme işleminde görülen durumdur. Nesne yenidir ve SaveChanges() metodu çağırılmamıştır. SaveChanges() ile birlikte değişiklikler kaydedildikten sonra nesnenin durumu “Unchanged” olarak değişir.

Örnek:

State: Added

SaveChanges() metodu ile birlikte değişiklikler db’ye yansıtıldıktan sonra:

State: Unchanged

Modified State

Nesnenin herhangi bir özelliğinin değeri DbContext kapsamında değiştirilirse, nesnenin durumu Modified olarak değişir. Nesne üzerinde bir değişiklik vardır ve SaveChanges() metodu çağırılmamıştır. Added State gibi SaveChanges() metodundan sonra durumu Unchanged olarak değişir.

Örnek:

State: Modified

SaveChanges() metodu ile birlikte değişiklikler db’ye yansıtıldıktan sonra:

State: Unchanged

Deleted State

Nesnenin contextten silindiği anda aldığı durumdur. Değişiklikler kaydedildikten sonra nesnenin durumu Detached olarak değişir.

Örnek:

State: Deleted

SaveChanges() metodu ile birlikte değişiklikler db’ye yansıtıldıktan sonra:

State: Detached

Detached State

Nesnenin var olduğu ama izlenmediği durumlarda aldığı durumdur. Nesne oluşturulduktan hemen sonra ve contexte eklenmeden önce bu durumdadır. Ayrıca yukarıdaki örnekte gördüğümüz gibi nesne contextten kaldırılırsa yine bu durumu alır.

Örnek:

Nesne scope dışında (context bağlamının içerisinde bulunmuyor)

Gördüğünüz gibi bir nesnenin bağlam içerisindeyken bulunabileceği 5 durumu inceledik. Peki bir nesnenin veya sorgunun izlenmemesini sağlayabilir miyiz?

Tracking vs. No-Tracking Queries

Standart bir senaryoda, default olarak, Entity Framework aracılığıyla bir veritabanından seçilen tüm varlıklar yukarıda anlattığımız gibi izlenir. “İzleme” kelimesinden kastımız, contextimizin izlenen nesneyi gözlemlediği ve üzerinde herhangi bir değişiklik yapılıp yapılmadığını bildiğidir. Bu izleme sonucunda SaveChanges() metodu çalıştığında, nesne üzerinde bir değişiklik varsa veritabanına yansıtılır.

Örnek bir tracking query (izlenen sorgu):

Peki sorgularımızın izlenmesini istemiyorsak?

No-Tracking Queries

Bir önceki “Generic Repository Pattern & ASP.NET Core” yazımda ufaktan değinmiştim aslında. Sonuçların read-only olduğu senaryolarda, daha açmak gerekirse, veritabanında hiçbir değişiklik yaratmayacak ve sadece okuma işlemi yapacağımız senaryolarda aşırı kullanışlı olan sorgu tipidir. Çünkü herhangi bir değişiklik olmadığı için daha hızlı sonuç verecektir. Bundan dolayı veritabanından aldığınız bir veriyi güncellemeniz gerekmiyorsa, izleme gerektirmeyen bir sorgu kullanmanız performans açısından da daha faydalı olacaktır.

AsNoTracking() for No-Tracking

AsNoTracking metodu ile sorguları no-tracking sorgular haline getirebiliyoruz. Yani read-only olan bir sorgu ardından gereksiz bir update işlemini ortadan kaldırıyoruz ve izleme işlemini bu metodun kullanıldığı nesne için kapatıyoruz.

Ayrıca sadece nesne ile sınırlı kalmayıp bütün bir contexti de izlemeye aşağıdaki kod ile kapatabiliriz:

context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;

Bu koddan sonra sorguları normal bir şekilde AsNoTracking metodu eklemeden kullanabilirsiniz.

EF Core, keyless entity tipindeki hiçbir şeyi izlemez.

Eveet bir yazının daha sonuna geldik. Umarım biraz da olsa birilerine katkıda bulunacaktır bu yazı. Kendinize çok iyi ve sağlıklı bakın, kodla kalın! :)

--

--