Cannot be tracked… hatası entity framework core’da yaşadığım bir hatadır. Bu hatayı çözümü ile beraber bir makaleye dökmek istedim. Benim gibi çözüme kavuşmak isteyenler için faydalı olacaktır.
“Cannot be tracked … key value for {‘Id’} is already being tracked” Hatası ve Çözümü
Hatanın tam hali ise şu şekildedir;
The instance of entity type cannot be tracked because another instance of this type with the same key is already being tracked
Hatadan anlaşılaşacağı üzere entityframework’de tracking adında bir yapı mevcut ve bu yapı sizin veritabanından çektiğiniz entity nesneleri üzerinde yaptığınız değişiklikleri takip etme ve update gibi işlemlerinizde hangi alanların güncelleneceği gibi durumlarda kolaylık sağlaması açısından faydalı olmaktadır.
Peki böyle bir ihtiyaçtan nasıl olurda hata yaşamış olabilir ya da diğer bir soru nasıl yanlış bir işlem yaptıkta böyle bir hata aldık?
Entity framework’de verileri nesnel olarak elde etmek ve herhangi bir sql sorgusu olmadan nesneler ve otomatik tamamlanan alan adları üzerinden işlem yapmak büyük kolaylık ve yönetilebilirlik sağlıyor. Fakat entityframework sorguları düzgün yazılmadığında ya da tüm yetkinlikleri bilmeden kodlama yaptığımızda bu tür hatalar ile karşılaşabiliyoruz.
Alttaki örnek kod bloğundan yola çıkacak olursak eğer siz entityframework’den elde ettiğiniz entity nesnesinin takip edilmesini istemiyorsanız bu durumda AsNoTracking metodunu kullanabilirsiniz.
1 2 | Product Products = await _context. Products.AsNoTracking().FirstOrDefaultAsync(x => x.Id == id); return Products; |
Eğer üstteki kod bloğundan AsNoTracking kullanmazsanız ve aynı oturumda Aynı Product nesnesine erişip üzerinde işlem yapıp ardından Update gibi bir süreç başlatırsanız başlıkta yer aldığınız hatayı yaşamanız olasıdır.
Bu durumda eğer sadece gösterim yapacaksak ve gösterim yaptığımız için entity nesnesini sonradan bir update sürecine falan sokmayacaksak AsNoTracking diyerek entity nesnesi üzerindeki değişikliklerin takip edilmemesini sağlayabilirsiniz.
Eğer bu duruma genel bir çözüm bulmak isterseniz şöyle bir Extension işinizi görecektir.
1 2 3 4 5 6 7 8 9 10 11 12 | public static void DetachLocal<T>(this DbContext context, T t, string entryId) where T : class, IIdentifier { var local = context.Set<T>() .Local .FirstOrDefault(entry => entry.Id.Equals(entryId)); if (!local.IsNull()) { context.Entry(local).State = EntityState.Detached; } context.Entry(t).State = EntityState.Modified; } |
Üstteki kod bloğu DbContext nesnesi için yazılmış bir extension’dır. Bu extension sayesinde DbContenxt içerisinde verdiğiniz entity nesnesi ve entityId ile ilgili bir kayıt elde edilirse bu kayıt detach edilerek. Ardından sizin vereceğiniz yeni entity nesnesi EntityState.Modified enum değeri ile attach edilecektir. Böylelikle aynı entity nesnesi için birden fazla kayıt olması durumunda mevcut entity nesneniz öncesindeki entity nesneleriniz dikkate alınmayacaktır.
Fakat bu kod bloğuna gerek kalmadan AsNoTracking kod bloğunu belirttiğim kurallar çerçevesinde kullanmaya özen gösterin.
Üstteki extension’ın örnek kullanımı ise bu şekilde olacak.
1 2 | _context.DetachLocal(tmodel, id); _context.SaveChanges(); |
Çok faydalandım paylaşımınızdan. Teşekkür ederim