ienumerable-ve-iqueryable-interfeyslerinin-ferqi

IEnumerable və IQueryable interfeyslərinin fərqi

Növbəti intervyu sualı.. “IEnumerable və IQueryable interfeyslərinin fərqi nədir?” Yəqin məqalənin oxucuları bir neçə dəfə bu sualı özlərinə veriblər və ya intervyularda bu sualla rastlaşıblar. 

               PS: IEnumerable və IEnumerator interfeysləri haqda məlumata malik deyilsinizsə, bu məqaləmizdən həmin interfeyslərlə tanış ola bilərsiniz.


Ön söz

C#-ın  3.0 versiyasında gələn ən əsas yenilik LINQ sorğuların yaradılması olub. Məhz IEnumerable və IQueryable interfeyslərinin fərqləndirilməsi məsələsi LINQ sorğular(LINQ query) zamanı ortaya çıxır.

LINQ özündə müxtəlif data konteynerlərə eyni API üzərindən sorğu verə bilmək imkanını saxlayır. Bu sorğular təkcə in-memory kolleksiyalar(massiv,kolleksiya,ümumiləşmə və.s) yox, həmçinin out-memory (database,json, xml vəs.) kolleksiyalara da tətbiq oluna bilir. Əgər massiv, kolleksiya, ümumiləşmələrə LINQ sorğular versək görərik ki, geriyə qayıdan nəticələr əksər hallarda çoxluq olaraq IEnumerable tipindədir. Amma out-memory ilə işləyən zaman əksər hallarda nəticə IQueryable tipində olur.

               IEnumerable generic interfeysi kolleksiyalardakı generic olmayan IEnumerable interfeysindən törəyib və GetEnumerator metoduna malikdir.

public interface IEnumerable< out T > : IEnumerable
    {
        IEnumerator< T > GetEnumerator();
    }

               IQueryable interfeysi də IEnumerable interfeysindən törəyib amma Expressionlarla işləyərək dinamik sorğular yaratmaq üçün istifadə olunur.

 public interface IQueryable : IEnumerable
    {
            Expression Expression { get; }
            Type ElementType { get; }
            IQueryProvider Provider { get; }
    }

 

               IEnumerable və IQueryable interfeysinin teoriyada fərqləri:

1)Qeyd etdiyimiz kimi, əgər çoxluq(massiv, kolleksiya və.s) operativ yaddaşdadırsa ozaman IEnumerable interfeysi istifadə olunur , əgər out-memory(yəni database, xml collection, json datas,dataset və.s) çoxluq üzərində əməliyyat aparılırsa geriyə qayıdan nəticə IQueryable tipində olur.

2)IEnumerable operativ yaddaşda yalnız irəliyə doğru oxuma əməliyyatlar aparmaq üçün istifadə oluna bilir(move forward) amma İQueryable interfeysi həm irəliyə həm də geriyə doğru oxuma əməliyyatları aparma qabiliyyətinə malikdir.

3)IEnumerable sorğusu bütün məlumatları operativ yaddaşa toplayır, beləki əgər alınan çoxluq üzərindən filtr, sort və.s proseslər yerinə yetirilərsə həmin proses operativ yaddaşda baş verir!    IQueryable interfeysində isə məlumatlar operativ yaddaşa toplanmır!!. Əvvəlcə bütün query toplanır, həmin query əsasında data konteynerə cəmi 1 sorğu gedir və əgər filtr, sort kimi proseslər lazım olarsa həmin proseslər operativ yaddaşda yox, misalçün bazada baş verir. Bu isə bütün məlumatı boşuna operativ yaddaş yükləməyin qabağını alır.

Sadə dillə izah: Bazada 100 sətir məlumat var. Sən bu sətirləri geriyə IEnumerable kimi alsan, ozaman bütün 100 məlumat gəlib yığılır Operativ yaddaşa. İndi bu məlumatlara Where,Select kimi extension metodlar tətbiq etsən operativ yaddaşdakı məlumatların üzərində iş görmüş olacaqsan. Amma sənin metodun geriyə İqeuryable qaytarsa sən hələ də bazaya qoşulu vəziyyətdəsən və məlumatlar operativ yaddaşda deyil. Sən indi ühere ,select yazsan bu sorğu gedib SQL-də original Where,Select sorğusuna çevriləcək və boşuna yaddaş şişməsinin qabağını almış olacaqsan.

IEnumerable və IQueryable interfeysinin praktikada fərqləri:

Yuxarıda dediklərimizi praktiki nümunə üzərində izah edək. Bunun üçün sadə bir console app düzəldək və Entity Framework Code First istifadə edək.

Proyektimizdə Person adlı klas yaradaq.

namespace IEnumerableVsIQueryable
{
    public class Person
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string Surname { get; set; }
        public string Email { get; set; }
        public bool IsEmailConfirmed { get; set; }
        public string Password { get; set; }


        public override string ToString()
        {
            return $"Name = {Name} ,Surname = {Surname}\n Email = {Email} ,IsEmailConfirmed = {IsEmailConfirmed}";
        }
    }
}

EF code first-ü konfiq edib bazanı update edək.

  public class AppDbContext : DbContext
    {
        public AppDbContext() : base("appDb") { }
        public DbSet People { get; set; }
        
    }


namespace IEnumerableVsIQueryable.Migrations
{
    using System.Data.Entity.Migrations;
    using System.Linq;


    internal sealed class Configuration : DbMigrationsConfiguration
    {
        public Configuration()
        {
            AutomaticMigrationsEnabled = false;
        }


        protected override void Seed(IEnumerableVsIQueryable.AppDbContext context)
        {
            //add test datas
            if (!context.People.Any())
            {
                Person[] people = new Person[]
                {
                   
                    new Person{ Email="satoru@gmail.com", IsEmailConfirmed=true,
                     Name ="Satoru", Password="@#$R@DEC@#$", Surname="Fujinuma"},
                     new Person{ Email="airi@gmail.com", IsEmailConfirmed=true,
                     Name ="Airi", Password="@#$R@DEC@#$", Surname="Katagiri"},
                      new Person{ Email="kayo@gmail.com", IsEmailConfirmed=true,
                     Name ="Kayo", Password="@#$RDwewe", Surname="Hinazuki"},
                       new Person{ Email="sachiko@gmail.com", IsEmailConfirmed=true,
                     Name ="Sachiko", Password="23534t5324edSDF", Surname="Fujinuma"},
                        new Person{ Email="kenya@gmail.com", IsEmailConfirmed=true,
                     Name ="Kenya", Password="@#@#$@#4dd32", Surname="Kobayashi"}


                };
                context.People.AddOrUpdate(people);
            }
            
        }
    }
}


 < connectionStrings >
    < add connectionString="Data Source=.;Initial Catalog=IEvsIQ;Integrated Security=SSPI;" name="appDb" providerName="System.Data.SqlClient" />
  connectionStrings >

Indi ilk nümunəmizi IEnumerable interfeysi ilə yazaq:

using System.Collections.Generic;
using System.Linq;
using static System.Console;
namespace IEnumerableVsIQueryable
{
    class Program
    {
        static void Main(string[] args)
        {
            List< Person > response;


            using (AppDbContext appDbContext = new AppDbContext())
            {
                //log sql queries to console output
                appDbContext.Database.Log = (str) => WriteLine(str);


                //get data as IEnumerable
                IEnumerable< Person > people = appDbContext.People;
                
                //and then filter it
                response = people.Where(x => x.Surname.StartsWith("Fuji")).ToList();
                
            }


            Show(response);
            ReadLine();
        }
        private static void Show(IEnumerable people)
        {
            foreach (Person person in people)
            {
                WriteLine(person);
            }
        }
    }
}


Alınan nəticə:


İndi isə kod nümunəsini İQueryable interfeysinə çevirək:

.....................
using (AppDbContext appDbContext = new AppDbContext())
            {
                //log sql queries to console output
                appDbContext.Database.Log = (str) => WriteLine(str);


                //get data as IQueryable
                IQueryable people = appDbContext.People;
                
                //and then filter it
                response = people.Where(x => x.Surname.StartsWith("Fuji")).ToList();
                
            }
...........................

Bu kodun icrasında alınan cavab:


Yuxaırdakı misaldan göründüyü kimi, IQueryable interfeysi sorğunu data source-a(burada database) verir, amma İEnumerable məlumatlara sorğunu operativ yaddaşda verir.


Bundan sonra güman edirəm ki, bu sualı sizə verənlərə cavabınız : “Şah və mat..” olacaq. Uğurlar..

Tural

Tural Süleymani

Süleymani Tural Microsoft-un MCSD statuslu mütəxəssisidir, 2008-ci ildən bu yana proqramlaşdırma üzrə tədris aparır

Müəllifin bu dildə ən son postları

Bu yazıları da bəyənə bilərsiniz