IEnumerable ve IQueryable çoğu geliştirici tarafından kullanımı karıştırılmakta ve ne zaman nerede kullanılacağı bilinmemektedir. Kod yazım tipleri birbirine çok benzerdir. Fakat kullanım yerleri işlevselliklerine göre değişir. Yanlış kullanımlar sistem performansını oldukça kötü etkiler.
Repository kullanarak Get ile bir Domain Object Collectionu (GetUsers, GetProduct) geriye dönmek istediğimizde bir kaç dönüş türü arasında seçim yapabiliriz.
- IQueryable<T>
- IEnumerable<T>
- IReadOnlyList<T>
Yukarıdaki return typelerden herhangi birini seçmemiz uygulamamızın performansını, tasarımını ve sürdürülebilirliğini etkileyebilir. Bu nedenle bilinçli bir seçim yaparak projemizin Access Layerını oluşturmalıyız.
Yukarıdaki bir
User sınıfımız ve
AppDBContext isminde bir contextimiz olduğunu düşünelim.
IQueryable<T> Return Type
IQueryable<T> interfacesi, C# expressionlarını direkt olarak veritabanı tarafında execute edilebilecek T-SQL sorgularına dönüştürmemize olanak tanır.
Fakat burada yazılan sorgunun sonuna ToList() demedikçe databaseye sorgu atılmayacaktır.
Yukarıda GetUsers() metodunun resultı bizim için hazır bir T-SQL sorgudur. Henüz databaseden kayıt çekilmemiştir.
Önemli Detaylar- Veritabanı sorgusu, yalnızca sonuç gerçekten istendiğinde execute edildi.(GetUsers() ta değil, yalnızca ToList() yöntemi çağrılırken).
- Where ifadeleri ekleyerek sorgu hazırlanmaya devam ediyoruz. Hala veritabanından kayıt çekmedik
- ToList() metodunu ekleyerek artık filtrelerle( where vs.) hazırladığımız sorguyu veritabanına gönderiyoruz.
Yukarıdaki şekilde bir tane Repository içerisine GetUsers() metodu yazılır ve bu repositoryi kullanan her yerden GetUserrs() metodunu çağırıp where koşulu eklenerek istenen sorgular dinamik bir şekilde hazırlanabilir. Fakat bu kullanımında dez avantajları vardır.
1- Dublicate Domain Rules
Örneğin Aktif kullanıcı listesi diye bir Domain kuralımız olduğunu ve kuralın bir çok servis tarafından kullanıldığını düşünelim. Tüm servislerin içerisinde aşağıdaki gibi kullanılsın.
Daha sonra aktif userın domain kuralın değiştiğini ve son bir yıldan önce kaydedilmiş kişilerin aktif user olduğu kuralı eklediğimizi düşünelin. Yukarıdaki kodun geçtiği her yere gidip güncelleme yapmamız aşağıdaki şekilde güncelleme yapmamız gerekecektir.
Bu nedenle, codebase bakımı daha zor hale gelir çünkü birkaç yerin güncellenmesi gerekir ve bir şeyler kolayca gözden kaçabilir.
IEnumerable<T> Return Type
IEnumrable<T> yapılan sorgularda filtreler(where vs.) T-SQL sorgusuna çevrilmez. İlk olarak DB den bütün kayıtlar çekilir ve belleğe kaydedilir. Daha sonra bu belleğe alınmış kayıtlar üzerinde filtreler yani where koşulları uygulanır.
İlk bakışta aynı duran yukarıdaki 2 kod satırı aynı zamanda aynı sonucu dönüyorlar fakat arka planda çalışma prensipleri farklı. Şöyle ki, IQueryable olan 1.satır direkt olarak sunucuda çalışacağı için belirtilen tablodan ilk 10 değeri atlayıp ikinci 10 satırı çeker. IEnumerable ise tüm satırları çeker ve hepsini bellekte tutar daha sonra ilk 10 kaydı atlayıp ikinci 10 kaydı gösterir. Aslında IEnumerable'da tüm tabloyu tutuyor ve hala diğer değerlerle ilgili işlem yapılabilir.
fark 2
Burada kodu derlemek istediğimizde her hangi bir hata ile karşılaşmayız, fakat run time'de kod hata fırlatır. Bunun sebebi T-SQL içinde Convert.ToInt32() metodunun olmayışıdır. Çünkü IQueryable sorguyu sunucuda derler demiştik. Bunun aşağıdaki şekilde çalıştırdığımızda her hangi bir hata ile karşılaşmayacağız.
IEnumerable, IQueryable tersine sorguyu sunucuda çalıştırmaz. Önce tüm verileri belleğe alır demiştik, daha sonra alınan verilere filtreleme işlemi yapıyoruz. Doğal olarak artık Convert.ToInt32() ile her hangi bir problem yaşamıyoruz.
IEnumerable Linq => Object işlemlerinde daha yararlı iken IQueryable Linq => Sql işlemlerinde daha kullanışlıdır.
İkisi de "Deferred Execution" destekler. Türkçesi ertelenmiş çalışmadır. Şöyle ki Linq sorguları hemen çalışmaz. Belirli bir komuta kadar bekler. Bunu tetikleyenlerden bir tanesi de ToList() metodudur. Sorgu düzenlenir, fakat çalıştırılmaz ta ki ToList() metodu çağrılır ve veri tabanına istek yapılıp veri getirilir.
IReadOnlyList<T> Return Type
IReadOnlyList, C# programlama dilinde bir interface'tir. IReadOnlyList, bir liste gibi düzenlenmiş verileri depolayan ve bu verilere sadece okuma işlemleri yapmaya izin veren bir yapıdır. IReadOnlyList, bir dizinin içeriğini değiştirmek için kullanılamaz ancak verileri okumak ve kullanmak için kullanılabilir. Bu interface, hem performans hem de güvenlik açısından avantajlıdır ve C# programlama dilinde sıklıkla kullanılır.
Add,Remove vs işlemleri IReadOnlyList üzerinde yapılamaz.
Reference