IQueryable <T> ve IEnumerable <T> arasındaki fark nedir?


Yanıtlar:


258

Her şeyden önce, genişleten bir "düz" ile yapabileceğiniz şey, böylece arayüz , aynı zamanda bir ile yapabilirsiniz .IQueryable<T> IEnumerable<T>IEnumerable<T>IQueryable<T>

IEnumerable<T>Sadece bir yer alır GetEnumerator()kullanıcıya bir yöntemi Enumerator<T>, onun çağırabilmesi için MoveNext()bir dizi boyunca yineleme yöntemini T .

Ne IQueryable<T>olduğunu etmiştir IEnumerable<T> gelmez bir işaret söz konusu-birinde iki özellik vardır sorgu sağlayıcısına bir etmek (örneğin, SQL sağlayıcısına bir LINQ) ve başka bir işaret sorgu ifadesinde temsilIQueryable<T> olabilecek bir çalışma zamanı-çaprazlanabiliyorsa soyut sözdizimi ağacı olarak nesneyi verilen sorgu sağlayıcısı tarafından anlaşılır (çoğunlukla, bir istisna oluşturulmadan LINQ to Entities sağlayıcısına SQL ifadesine bir LINQ veremezsiniz).

İfade, nesnenin kendisinin sabit bir ifadesi veya oluşturulmuş bir sorgu işleçleri ve işlenenler kümesinden daha karmaşık bir ağaç olabilir. Sorgu sağlayıcısının IQueryProvider.Execute()veya IQueryProvider.CreateQuery()yöntemlerinin kendisine iletilen bir İfade ile çağrılır ve ardından IQueryablesırasıyla bir sorgu sonucu veya başka bir sonuç döndürülür.


8
AsQueryable'ı kullanmanın herhangi bir faydası var mı?
Ürdün

6
Tek fayda kolaylık. AsQueryable()sadece bir sorgulanabilir numaraya numaralandırılır ve IQueryablearabirimi uygularsa geri döndürür , aksi takdirde ConstantExpressiondöndürülen bir EnumerableQuerynesnede atıfta bulunulan a'ya sarar .
Mark Cidade


1
Bunu okumaya değer makaleyi
JenonD

@JenonD bağlantısı öldü, işte geri dönüş makinesi: web.archive.org/web/20160904162931/http://www.dotnet-tricks.com/…
majjam 15:18

201

Birincil fark, temsilciler yerine nesne IQueryable<T>almak için LINQ operatörlerinin Expression, yani aldığı bir özel sorgu mantığı, örneğin bir yüklem veya değer seçici gibi, bir yönteme temsilci yerine bir ifade ağacı biçiminde olmasıdır.

  • IEnumerable<T> bellekte yinelenen dizilerle çalışmak için mükemmeldir, ancak
  • IQueryable<T> veritabanı veya web hizmeti gibi uzak veri kaynağı gibi bellek dışı şeylere izin verir.

Sorgu yürütme:

  • Bir sorgunun yürütülmesi "işlemde" gerçekleştirilecekse , genellikle gerekli olan tek şey, sorgunun her bir parçasını yürütmek için kullanılan koddur (kod olarak).

  • Yürütme işlem dışında gerçekleştirilecekse , sorgunun mantığı, LINQ sağlayıcısının, bu bir LDAP sorgusu olsun, bellek dışı yürütme için uygun forma dönüştürülebileceği şekilde verilerde temsil edilmelidir SQL ya da her neyse.

Daha:

http://www.codeproject.com/KB/cs/646361/WhatHowWhere.jpg


14
Bellek yetersiz işlemlerden bahsetmeyi seviyorum. Kullanımdaki gerçek pratik farkı açıklığa kavuşturur.
Ishmael Smyrnow

2
Temsilcileri IEnumerable <T> gibi parametreler olarak almak yerine, IQueryable <T> Expression <TDelegate> parametrelerini alır. Kodu IQueryable <T> içine geçirmiyoruz, LINQ sağlayıcısının analiz etmesi için ifade ağaçlarını (veri olarak kod) geçiriyoruz. C # 3.0 ve LINQ
Lu55

resim bağlantınızla ilgili bir şey var, bazı nedenlerden dolayı yazı gövdesinde görüntülenmiyor codeproject.com/KB/cs/646361/WhatHowWhere.jpg
jbooker

@joey Yine de, bu cevapta bu görüntüyü gayet iyi görüyorum: i.stack.imgur.com/2DAqv.jpg
VonC

190

Bu, youtube'da , bu arayüzlerin nasıl farklı olduğunu, izlemeye değer olduğunu gösteren güzel bir video .

Aşağıda bunun için uzun bir açıklayıcı cevap bulunmaktadır.

Hatırlanması gereken ilk önemli noktadır IQueryablegelen arayüz devralır IEnumerable, her neyse IEnumerableyapabilir, IQueryableayrıca yapabilirsiniz.

resim açıklamasını buraya girin

Birçok fark var ama en büyük farkı yaratan tek büyük fark hakkında konuşalım. IEnumerablearayüzü, koleksiyonunuz kullanılarak yüklendiğinde kullanışlıdır.LINQ veya Entity framework ve koleksiyona filtre uygulamak istediğinizde .

IEnumerableVarlık çerçevesi ile birlikte kullanılan aşağıdaki basit kodu göz önünde bulundurun . Bir kullanıyor Whereolan kayıtları almak için filtre EmpIdolduğunu 2.

EmpEntities ent = new EmpEntities();
IEnumerable<Employee> emp = ent.Employees; 
IEnumerable<Employee> temp = emp.Where(x => x.Empid == 2).ToList<Employee>();

Bu, filtrenin IEnumerablekodun bulunduğu istemci tarafında yürütüldüğü yerdir . Bir başka deyişle, tüm veriler veritabanından getirilen ve daha sonra onun taramaları istemcide ile kayıt almaktadır EmpIdolduğunu 2.

resim açıklamasını buraya girin

Ama şimdi değişti aşağıdaki kodu görmek IEnumerableiçin IQueryable. Sunucu tarafında bir SQL Sorgusu oluşturur ve istemci tarafına yalnızca gerekli veriler gönderilir.

EmpEntities ent = new EmpEntities();
IQueryable<Employee> emp = ent.Employees;
IQueryable<Employee> temp =  emp.Where(x => x.Empid == 2).ToList<Employee>();

resim açıklamasını buraya girin

Arasındaki fark Yani IQueryableveIEnumerable filtre mantığı gerçekleştirildiği yer hakkındadır. Biri istemci tarafında, diğeri veritabanında yürütülür.

Bu yüzden sadece bellek içi veri toplama ile çalışıyorsanız IEnumerableiyi bir seçimdir, ancak veritabanına bağlı veri toplama sorgulamak istiyorsanız `IQueryable ağ trafiğini azalttığı ve SQL dilinin gücünü kullandığı için daha iyi bir seçimdir.


Merhaba, harika bir açıklama için çok teşekkürler. Neden IQueryable "bellek yetersiz" veri için daha iyi bir seçim olduğunu anlıyorum ama IEnumerable neden "bellek içi" veri için daha iyi olduğunu anlamak için mücadele? Filtrelenmiş veri almanın, veri almak ve filtre uygulamaktan daha iyi olduğunu düşünüyorum.
İmad

"bellek içi" olduğunda gerçekten önemli değil. veriler zaten bellekte, ne zaman filtrelendiği önemli değil.
Roni Axelrad

@Imad Örneğin, DateTimeOffset öğesi DateTime'a dönüştürülerek veri yansıtma IQueryable veya EntityFunctions ile gerçekleştirilemez. En iyi yol, varlık nesnesini AsEnumerable (), sonra da DateTime içeren bir görünüm modelinde () öğesini seçmektir. Bu işlem bellek içi işlevleri kullanır.
Jeff Li

57

IEnumerable: IEnumerable, bellek içi toplama (veya yerel sorgular) ile çalışmak için en uygun yöntemdir. IEnumerable öğeler arasında hareket etmiyor, sadece ileriye doğru toplama.

IQueryable: Veritabanı veya web hizmeti (veya uzak sorgular) gibi uzak veri kaynağı için en uygun IQueryable. IQueryable çeşitli ilginç ertelenmiş yürütme senaryoları (sayfalama ve kompozisyon tabanlı sorgular gibi) sağlayan çok güçlü bir özelliktir.

Bu nedenle, sadece bellek içi koleksiyonu yinelemeniz gerektiğinde, IEnumerable kullanın, Veri Kümesi ve diğer veri kaynakları gibi koleksiyonla herhangi bir manipülasyon yapmanız gerekiyorsa, IQueryable kullanın


3
IEnumerable ertelenmiş yürütme kullanmıyor mu?
Ian Warburton

3
Ertelenmiş yürütme hem IEnumerable hem de IQueryable olarak kullanılabilir. Daha ilginç bilgiler burada bulunabilir: stackoverflow.com/questions/2876616/…
Ignacio Hagopian

18

Basit bir ifadeyle diğer önemli fark, IEnumerable'ın sunucu tarafında seçme sorgusu yürütmesi, istemci tarafında belleğe veri yüklemesi ve daha sonra verileri filtrelemesi, IQueryable ise tüm filtrelerle sunucu tarafında seçme sorgusu yürütmesidir.


17

Gerçek hayatta, eğer LINQ-to-SQL gibi bir ORM kullanıyorsanız

  • Bir IQueryable oluşturursanız, sorgu sql'ye dönüştürülebilir ve veritabanı sunucusunda çalıştırılabilir
  • Bir IEnumerable oluşturursanız, sorguyu çalıştırmadan önce tüm satırlar nesneler olarak belleğe alınır.

Her iki durumda da bir ToList()veya ToArray()daha sonra sorguyu kullanmazsanız, sorgu her kullanıldığında yürütülür, yani diyelim ki, ondan bir IQueryable<T>liste kutusu doldurursunuz ve sorgu 4 kez veritabanında çalıştırılır.

Ayrıca sorgunuzu genişletirseniz:

q.Where(x.name = "a").ToList()

Daha sonra bir IQueryable ile oluşturulan SQL “nerede name =“ a ”içerecektir, ancak bir IEnumerable ile daha birçok rol veritabanından geri alınacak, daha sonra x.name =“ a ”kontrolü .NET tarafından yapılacaktır.


10

IEnumerable bir koleksiyona atıfta bulunuyor ancak IQueryable sadece bir sorgu ve bir İfade Ağacı içinde oluşturulacak. Veritabanından veri almak için bu sorguyu çalıştıracağız.


8

Aşağıda belirtilen küçük test IQueryable<T>ve ile arasındaki farkın bir yönünü anlamanıza yardımcı olabilir IEnumerable<T>. Başka bir kişinin gönderisine düzeltme eklemeye çalıştığım bu gönderiden bu yanıtı yeniden oluşturdum

Ben DB (DDL komut dosyası) aşağıdaki yapı oluşturdu:

CREATE TABLE [dbo].[Employee]([PersonId] [int] NOT NULL PRIMARY KEY,[Salary] [int] NOT NULL)

İşte kayıt ekleme komut dosyası (DML komut dosyası):

INSERT INTO [EfTest].[dbo].[Employee] ([PersonId],[Salary])VALUES(1, 20)
INSERT INTO [EfTest].[dbo].[Employee] ([PersonId],[Salary])VALUES(2, 30)
INSERT INTO [EfTest].[dbo].[Employee] ([PersonId],[Salary])VALUES(3, 40)
INSERT INTO [EfTest].[dbo].[Employee] ([PersonId],[Salary])VALUES(4, 50)
INSERT INTO [EfTest].[dbo].[Employee] ([PersonId],[Salary])VALUES(5, 60)
GO

Şimdi, amacım Employeeveritabanındaki tablodan en iyi 2 kaydı almaktı. Konsol uygulamama Employeeveritabanımdaki tabloya işaret eden bir ADO.NET Varlık Veri Modeli öğesi ekledim ve LINQ sorguları yazmaya başladım.

IQueryable yolu için kod :

using (var efContext = new EfTestEntities())
{
    IQueryable<int> employees = from e in efContext.Employees  select e.Salary;
    employees = employees.Take(2);

    foreach (var item in employees)
    {
        Console.WriteLine(item);
    }
}

Bu programı çalıştırmaya başladığımda, SQL Server örneğimde bir SQL Query profiler oturumu başlatmıştım ve işte yürütmenin özeti:

  1. Toplam sorgu sayısı: 1
  2. Sorgu metni: SELECT TOP (2) [c].[Salary] AS [Salary] FROM [dbo].[Employee] AS [c]

Sadece yan tümcesi veritabanı sunucu tarafı kendisi IQueryableuygulamak için yeterince akıllıdır, Top (2)böylece tel üzerinden 5 kayıt sadece 2 getiriyor. İstemci bilgisayar tarafında daha fazla bellek içi filtreleme gerekmez.

Sayılabilir rota kodu :

using (var efContext = new EfTestEntities())
{
    IEnumerable<int> employees = from e in efContext.Employees  select e.Salary;
    employees = employees.Take(2);

    foreach (var item in employees)
    {
        Console.WriteLine(item);
    }
}

Bu durumda yürütmenin özeti:

  1. Toplam sorgu sayısı: 1
  2. SQL profil oluşturucuda yakalanan sorgu metni: SELECT [Extent1].[Salary] AS [Salary] FROM [dbo].[Employee] AS [Extent1]

Şimdi şey, tablodaki IEnumerable5 kaydın tümünü getirildi Salaryve daha sonra istemci bilgisayarda en iyi 2 kaydı almak için bir bellek içi filtreleme gerçekleştirildi. Böylece gereksiz yere tel üzerinden daha fazla veri (bu durumda 3 ek kayıt) aktarıldı.


7

İşte benzer bir yazıya yazdım (bu konuda). (Ve hayır, genellikle kendimi teklif etmiyorum, ama bunlar çok iyi makaleler.)

"Bu makale faydalıdır: LINQ-to-SQL'de IQueryable vs IEnumerable .

Bu makalede, 'MSDN belgelerine göre, IQueryable üzerinde yapılan çağrılar bunun yerine dahili ifade ağacını oluşturarak çalışır. "IQueryable'ı (Of T) genişleten bu yöntemler doğrudan sorgulama yapmaz. Bunun yerine, işlevleri birikimli sorguyu temsil eden bir ifade ağacı olan bir Expression nesnesi oluşturmaktır."

İfade ağaçları, C # ve .NET platformunda çok önemli bir yapıdır. (Genel olarak önemlidirler, ancak C # onları çok kullanışlı hale getirir.) Farkı daha iyi anlamak için, burada resmi C # 5.0 spesifikasyonundaki ifadeler ve ifadeler arasındaki farkları okumayı öneririm . Lamda analizine dalmış ileri teorik kavramlar için ifadeler birinci sınıf nesneler olarak yöntemlere destek sağlar. IQueryable ve IEnumerable arasındaki fark bu noktaya odaklanmıştır. IQueryable ifade ağaçları oluştururken IEnumerable, en azından genel anlamda, Microsoft'un gizli laboratuvarlarında çalışmayanlarımız için değildir.

İşte itme ve çekme perspektifinden farklılıkları ayrıntılarıyla anlatan bir diğer faydalı makale. ("Push" vs. "pull" ile veri akış yönüne atıfta bulunuyorum. .NET ve C # için Reaktif Programlama Teknikleri

Deyim lambdasları ve ifade lambdasları arasındaki farkları detaylandıran ve ifade gerilimi kavramlarını daha derinlemesine tartışan çok iyi bir makale: C # delegelerinin, ifade ağaçlarının ve lambda ifadelerinin lambda ifadelerine karşı yeniden gözden geçirilmesi. ."


6

Veritabanından alınan verileri kullanmak IEnumerableve IQueryableişlemek için kullanıyoruz . IQueryablemiras alır IEnumerable, IQueryabletüm IEnumerableözellikleri içerir. Arasındaki büyük fark IQueryableve IEnumerableolmasıdırIQueryable , oysa filtrelerle yürütür sorgu IEnumerablesorgu önce ve sonra şartlarına dayalı veriler filtreler çalıştırır.

Aşağıda daha ayrıntılı bir fark bulabilirsiniz:

IEnumerable

  1. IEnumerable içinde var System.Collections ad
  2. IEnumerable sunucu tarafında bir seçme sorgusu yürütme, bir istemci tarafında bellekte veri yükleme ve ardından verileri filtreleme
  3. IEnumerable Liste, Dizi gibi bellek içi koleksiyonlardaki verileri sorgulamak için uygundur
  4. IEnumerable LINQ to Object ve LINQ to XML sorguları için faydalıdır

IQueryable

  1. IQueryable içinde var System.Linq ad
  2. IQueryable tüm filtrelerle sunucu tarafında bir 'seçme sorgusu' yürütür
  3. IQueryable bellek dışı (uzak veritabanı, hizmet gibi) koleksiyonlarından veri sorgulamak için uygundur
  4. IQueryable LINQ to SQL sorguları için faydalıdır

Bu yüzden IEnumerablegenellikle bellek içi toplama ile uğraşırken IQueryable, genellikle koleksiyonları manipüle etmek için kullanılır.



2

IQueryable, veritabanından büyük miktarlarda veri ile uğraşırsak IEnumerable'dan daha hızlıdır, çünkü IQueryable, veritabanından gereklilikten bağımsız olarak IEnumerable olarak tüm verileri aldığı veritabanından yalnızca gerekli verileri alır


0

ienumerable: işlenmemiş bellekle uğraşmak istediğimizde, yani veri bağlantısı olmadan iqueryable: sql sunucusu ile ne zaman uğraşacağız, yani veri bağlantısı ilist: nesne ekleme, nesne silme vb.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.