LINQ

2009-10-16 12 views
205

के साथ IQueryable का उपयोग LINQ के संदर्भ में IQueryable का उपयोग क्या है?LINQ

क्या यह विस्तार विधियों या किसी अन्य उद्देश्य के विकास के लिए उपयोग किया जाता है?

उत्तर

421

Marc Gravell's answer बहुत पूरा हो गया है, लेकिन मैंने सोचा कि मैं देखने के उपयोगकर्ता के बिंदु से इस बारे में कुछ जोड़ना चाहते हैं, साथ ही ...


मुख्य अंतर यह है एक उपयोगकर्ता के नजरिए से, कि है, जब आप IQueryable<T> (एक प्रदाता के साथ जो सही तरीके से समर्थन करता है) का उपयोग करते हैं, तो आप बहुत सारे संसाधनों को बचा सकते हैं।

उदाहरण के लिए, यदि आप कई ओआरएम सिस्टम के साथ रिमोट डेटाबेस के खिलाफ काम कर रहे हैं, तो आपके पास एक टेबल से डेटा को दो तरीकों से लाने का विकल्प है, जो IEnumerable<T> देता है, और एक जो IQueryable<T> देता है। कहें, उदाहरण के लिए, आपके पास एक उत्पाद तालिका है, और आप उन सभी उत्पादों को प्राप्त करना चाहते हैं जिनकी लागत> $ 25 है।

यदि आप कार्य करें:

IEnumerable<Product> products = myORM.GetProducts(); 
var productsOver25 = products.Where(p => p.Cost >= 25.00); 

यहाँ क्या होता है, डेटाबेस लोड उत्पादों के सभी है, और अपने कार्यक्रम के लिए तार पर इन लोगों के पास करता है। आपका प्रोग्राम तब डेटा फ़िल्टर करता है। संक्षेप में, डेटाबेस SELECT * FROM Products करता है, और आपके लिए प्रत्येक उत्पाद देता है।

सही IQueryable<T> प्रदाता के साथ, दूसरे हाथ पर, आप कर सकते हैं:

IQueryable<Product> products = myORM.GetQueryableProducts(); 
var productsOver25 = products.Where(p => p.Cost >= 25.00); 

कोड एक ही है, लेकिन अंतर यह है कि एसक्यूएल निष्पादित SELECT * FROM Products WHERE Cost >= 25 हो जाएगा।

डेवलपर के रूप में आपके पीओवी से, यह वही दिखता है। हालांकि, एक प्रदर्शन के दृष्टिकोण से, आप केवल 2 रिकॉर्ड 20,000 के बजाय नेटवर्क भर में वापस आ सकते हैं ....

+7

पर बहुत सच्चाई "GetQueryableProducts();" की परिभाषा कहां है? – Pankaj

+9

@StackOverflowUser यह किसी भी विधि का इरादा है जो 'IQueryable ' देता है - आपके ORM या रिपॉजिटरी आदि के लिए विशिष्ट होगा –

+0

दाएं। लेकिन आपने बताया कि इस फ़ंक्शन कॉल के बाद खंड कहां है। तो सिस्टम अभी भी फ़िल्टर से अनजान है। मेरा मतलब है कि यह अभी भी उत्पादों के सभी रिकॉर्ड लाता है। सही? – Pankaj

164

संक्षेप में अपना काम बहुत IEnumerable<T> के समान है - एक queryable डेटा स्रोत का प्रतिनिधित्व करने के लिए - अंतर किया जा रहा है कि विभिन्न LINQ विधियों (Queryable पर) और अधिक विशिष्ट हो सकता है, प्रतिनिधियों के बजाय Expression पेड़ का उपयोग कर क्वेरी बनाने के लिए (जो क्या Enumerable उपयोग करता है)।

अभिव्यक्ति पेड़ों का आपके चुने हुए LINQ प्रदाता द्वारा निरीक्षण किया जा सकता है और वास्तविक क्वेरी में बदल गया - हालांकि यह स्वयं में एक काला कला है। उपयोगकर्ता लेकिन वास्तविकता में आप शायद ही कभी इस बारे में परवाह करने की जरूरत एक के रूप में -

यह वास्तव में ElementType, Expression और Provider करने के लिए नीचे है। केवल एक LINQ कार्यान्वयन को गोर विवरणों को जानने की आवश्यकता है।


पुन: टिप्पणियां; मुझे यकीन नहीं है कि आप उदाहरण के जरिए क्या चाहते हैं, लेकिन LINQ-to-SQL पर विचार करें; यहां केंद्रीय वस्तु DataContext है, जो हमारे डेटाबेस-रैपर का प्रतिनिधित्व करती है। इसमें आम तौर पर प्रति तालिका एक संपत्ति होती है (उदाहरण के लिए, Customers), और एक तालिका IQueryable<Customer> लागू करती है। लेकिन हम इसका अधिक उपयोग नहीं करते हैं; पर विचार करें:

using(var ctx = new MyDataContext()) { 
    var qry = from cust in ctx.Customers 
       where cust.Region == "North" 
       select new { cust.Id, cust.Name }; 
    foreach(var row in qry) { 
     Console.WriteLine("{0}: {1}", row.Id, row.Name); 
    } 
} 

इस (सी # संकलक द्वारा) हो जाता है:

var qry = ctx.Customers.Where(cust => cust.Region == "North") 
       .Select(cust => new { cust.Id, cust.Name }); 

जो फिर से (सी # संकलक द्वारा) के रूप में व्याख्या की है:

var qry = Queryable.Select(
       Queryable.Where(
        ctx.Customers, 
        cust => cust.Region == "North"), 
       cust => new { cust.Id, cust.Name }); 

महत्वपूर्ण बात, स्थिर तरीकों पर Queryable अभिव्यक्ति पेड़ लें, जो नियमित आईएल की बजाय, किसी ऑब्जेक्ट मॉडल में संकलित हो जाएं। उदाहरण के लिए - बस "कहां" को देखते हुए, यह हमें कुछ तुलनीय बनाता है:

var cust = Expression.Parameter(typeof(Customer), "cust"); 
var lambda = Expression.Lambda<Func<Customer,bool>>(
        Expression.Equal(
         Expression.Property(cust, "Region"), 
         Expression.Constant("North") 
       ), cust); 

... Queryable.Where(ctx.Customers, lambda) ... 

क्या संकलक हमारे लिए बहुत कुछ नहीं करता था? यह ऑब्जेक्ट मॉडल फाड़ जा सकता है, इसका क्या मतलब के लिए निरीक्षण किया, और वापस एक साथ फिर से TSQL जनरेटर द्वारा डाल - तरह कुछ दे रही है:

SELECT c.Id, c.Name 
FROM [dbo].[Customer] c 
WHERE c.Region = 'North' 

(स्ट्रिंग एक पैरामीटर के रूप अंत हो सकता है, मैं याद नहीं कर सकते)

यदि हम अभी एक प्रतिनिधि का उपयोग करते हैं तो इनमें से कोई भी संभव नहीं होगा। और यहQueryable/IQueryable<T> का बिंदु है: यह अभिव्यक्ति पेड़ का उपयोग करने के लिए प्रवेश बिंदु प्रदान करता है।

यह सब बहुत जटिल है, इसलिए यह एक अच्छा काम है कि संकलक हमारे लिए यह अच्छा और आसान बनाता है।

अधिक जानकारी के लिए, "C# in Depth" या "LINQ in Action" देखें, जिनमें से दोनों इन विषयों का कवरेज प्रदान करते हैं।

+2

यदि आपको कोई फर्क नहीं पड़ता है तो क्या आप मुझे सरल समझने योग्य उदाहरण के साथ अपडेट कर सकते हैं (यदि आपके पास समय है)। – user190560

+0

क्या आप समझ सकते हैं "GetQueryableProducts() की परिभाषा कहां है? "?" श्री रीड कोपेसी उत्तर में – Pankaj

+0

एक क्वेरी में अभिव्यक्तियों का अनुवाद करने की रेखा का आनंद लिया गया है "खुद में काली कला" ... – afreeland

2

यह आगे लाइन के आगे पूछताछ के लिए अनुमति देता है।यदि यह सेवा सीमा से परे था, तो इस IQueryable ऑब्जेक्ट के उपयोगकर्ता को इसके साथ और अधिक करने की अनुमति होगी।

उदाहरण के लिए यदि आप निबर्ननेट के साथ आलसी लोडिंग का उपयोग कर रहे थे तो परिणामस्वरूप ग्राफ को लोड होने पर लोड किया जा सकता है।

10
हालांकि Reed Copsey

और Marc Gravell पहले से ही IQueryable(and also IEnumerable) के बारे में पर्याप्त वर्णित है, हालांकि मैं एक small example on IQueryable and IEnumerable के रूप में उपलब्ध कराने के द्वारा यहां छोटे से अधिक जोड़ना चाहते हैं कई उपयोगकर्ताओं को इसके बारे में

उदाहरण पूछा: मैं डेटाबेस में दो टेबल बनाया है

CREATE TABLE [dbo].[Employee]([PersonId] [int] NOT NULL PRIMARY KEY,[Gender] [nchar](1) NOT NULL) 
    CREATE TABLE [dbo].[Person]([PersonId] [int] NOT NULL PRIMARY KEY,[FirstName] [nvarchar](50) NOT NULL,[LastName] [nvarchar](50) NOT NULL) 

तालिका Employee की Primary key(PersonId) भीहै तालिका Person

अगला कीमैं अपने आवेदन में ado.net इकाई मॉडल जोड़ा गया है और कि

public class SomeServiceClass 
{ 
    public IQueryable<Employee> GetEmployeeAndPersonDetailIQueryable(IEnumerable<int> employeesToCollect) 
    { 
     DemoIQueryableEntities db = new DemoIQueryableEntities(); 
     var allDetails = from Employee e in db.Employees 
         join Person p in db.People on e.PersonId equals p.PersonId 
         where employeesToCollect.Contains(e.PersonId) 
         select e; 
     return allDetails; 
    } 

    public IEnumerable<Employee> GetEmployeeAndPersonDetailIEnumerable(IEnumerable<int> employeesToCollect) 
    { 
     DemoIQueryableEntities db = new DemoIQueryableEntities(); 
     var allDetails = from Employee e in db.Employees 
         join Person p in db.People on e.PersonId equals p.PersonId 
         where employeesToCollect.Contains(e.PersonId) 
         select e; 
     return allDetails; 
    } 
} 

वे एक ही LINQ शामिल पर सेवा वर्ग नीचे पैदा करते हैं।यह program.cs में कहा जाता है के रूप में नीचे

class Program 
{ 
    static void Main(string[] args) 
    { 
     SomeServiceClass s= new SomeServiceClass(); 

     var employeesToCollect= new []{0,1,2,3}; 

     //IQueryable execution part 
     var IQueryableList = s.GetEmployeeAndPersonDetailIQueryable(employeesToCollect).Where(i => i.Gender=="M");    
     foreach (var emp in IQueryableList) 
     { 
      System.Console.WriteLine("ID:{0}, EName:{1},Gender:{2}", emp.PersonId, emp.Person.FirstName, emp.Gender); 
     } 
     System.Console.WriteLine("IQueryable contain {0} row in result set", IQueryableList.Count()); 

     //IEnumerable execution part 
     var IEnumerableList = s.GetEmployeeAndPersonDetailIEnumerable(employeesToCollect).Where(i => i.Gender == "M"); 
     foreach (var emp in IEnumerableList) 
     { 
      System.Console.WriteLine("ID:{0}, EName:{1},Gender:{2}", emp.PersonId, emp.Person.FirstName, emp.Gender); 
     } 
     System.Console.WriteLine("IEnumerable contain {0} row in result set", IEnumerableList.Count()); 

     Console.ReadKey(); 
    } 
} 

output is same for both जाहिर

ID:1, EName:Ken,Gender:M 
ID:3, EName:Roberto,Gender:M 
IQueryable contain 2 row in result set 
ID:1, EName:Ken,Gender:M 
ID:3, EName:Roberto,Gender:M 
IEnumerable contain 2 row in result set 

तो सवाल क्या/जहां अंतर है परिभाषित? ऐसा लगता है कि कोई फर्क नहीं पड़ता है? वास्तव में!!

के इन अवधि

IQueryable execution part

--IQueryableQuery1 
SELECT 
[Extent1].[PersonId] AS [PersonId], 
[Extent1].[Gender] AS [Gender] 
FROM [dbo].[Employee] AS [Extent1] 
WHERE ([Extent1].[PersonId] IN (0,1,2,3)) AND (N'M' = [Extent1].[Gender]) 

--IQueryableQuery2 
SELECT 
[GroupBy1].[A1] AS [C1] 
FROM (SELECT 
    COUNT(1) AS [A1] 
    FROM [dbo].[Employee] AS [Extent1] 
    WHERE ([Extent1].[PersonId] IN (0,1,2,3)) AND (N'M' = [Extent1].[Gender]) 
) AS [GroupBy1] 

IEnumerable execution part

--IEnumerableQuery1 
SELECT 
[Extent1].[PersonId] AS [PersonId], 
[Extent1].[Gender] AS [Gender] 
FROM [dbo].[Employee] AS [Extent1] 
WHERE [Extent1].[PersonId] IN (0,1,2,3) 

--IEnumerableQuery2 
SELECT 
[Extent1].[PersonId] AS [PersonId], 
[Extent1].[Gender] AS [Gender] 
FROM [dbo].[Employee] AS [Extent1] 
WHERE [Extent1].[PersonId] IN (0,1,2,3) 
के दौरान उत्पन्न और इकाई framwork 5 द्वारा निष्पादित एसक्यूएल प्रश्नों पर एक नजर है

Common script for both execution part

/* these two query will execute for both IQueryable or IEnumerable to get details from Person table 
    Ignore these two queries here because it has nothing to do with IQueryable vs IEnumerable 
--ICommonQuery1 
exec sp_executesql N'SELECT 
[Extent1].[PersonId] AS [PersonId], 
[Extent1].[FirstName] AS [FirstName], 
[Extent1].[LastName] AS [LastName] 
FROM [dbo].[Person] AS [Extent1] 
WHERE [Extent1].[PersonId] = @EntityKeyValue1',N'@EntityKeyValue1 int',@EntityKeyValue1=1 

--ICommonQuery2 
exec sp_executesql N'SELECT 
[Extent1].[PersonId] AS [PersonId], 
[Extent1].[FirstName] AS [FirstName], 
[Extent1].[LastName] AS [LastName] 
FROM [dbo].[Person] AS [Extent1] 
WHERE [Extent1].[PersonId] = @EntityKeyValue1',N'@EntityKeyValue1 int',@EntityKeyValue1=3 
*/ 

तो तुम कुछ सवाल अब है, मुझे उन लगता है और उन्हें जवाब देने के लिए

कुछ पता लगाना करने देता है की कोशिश यहां अंक,

सभी प्रश्नों एक आम हिस्सा

WHERE [Extent1].[PersonId] IN (0,1,2,3)

क्यों है? दोनों समारोह में बुला जबकि क्योंकि दोनों समारोह IQueryable<Employee> GetEmployeeAndPersonDetailIQueryable और SomeServiceClass की IEnumerable<Employee> GetEmployeeAndPersonDetailIEnumerable एक common line in linq queries

where employeesToCollect.Contains(e.PersonId)

से क्यों AND (N'M' = [Extent1].[Gender]) हिस्सा IEnumerable execution part में याद आ रही है, जिसका हम program.cs

में Where(i => i.Gender == "M") इस्तेमाल किया अब हम कर रहे हैं उस बिंदु पर जहां IQueryable और के बीच अंतर आया जब एक IQueryable विधि कहा जाता है, यह linq statement written inside the method tooks और लाने और constructs more appropriate sql query to execute करने की जरूरत है पता लगाने के लिए अगर more linq/expression is defind on the resultset, यह सब LINQ प्रश्नों परिणाम जब तक परिभाषित इकट्ठा कोशिश

क्या entity framwork करता है।

ऐसा लगता है कि लाभ के एक बहुत,

  • प्रदान केवल उन पंक्तियों एसक्यूएल सर्वर की आबादी जो पूरे LINQ क्वेरी निष्पादन द्वारा मान्य हो सकता है
  • अनावश्यक पंक्तियों
  • का चयन नहीं द्वारा एसक्यूएल सर्वर प्रदर्शन में मदद करता है
  • नेटवर्क लागत यहाँ उदाहरण एसक्यूएल सर्वर में तरह

को कम मिलता है केवल two rows after IQueryable execution आवेदन लेकिनके लिए लौट आएक्यों?

IEnumerable विधि के मामले में, entity framework विधि के अंदर लिखित लिखित कथन ले लिया और परिणाम प्राप्त करने के दौरान एसक्यूएल क्वेरी तैयार करता है। it does not include rest linq part to constructs the sql query। यहां कॉलम gender पर एसक्यूएल सर्वर में कोई फ़िल्टरिंग नहीं की गई है।

लेकिन आउटपुट समान हैं? चूंकि 'sql server

SO, किसी को चुनने के लिए परिणाम प्राप्त करने के बाद' एननेमेरेबल परिणाम को परिणाम स्तर पर आगे बढ़ाता है। मैं व्यक्तिगत रूप से IQueryable<T> के रूप में फ़ंक्शन परिणाम को परिभाषित करना पसंद करता हूं क्योंकि 'IEnumerable' पर बहुत सारे लाभ हैं, तो आप join two or more IQueryable function कर सकते हैं जो SQL सर्वर पर अधिक विशिष्ट स्क्रिप्ट उत्पन्न करता है।

उदाहरण में आप IQueryable Query(IQueryableQuery2)IEnumerable query(IEnumerableQuery2) से अधिक विशिष्ट स्क्रिप्ट उत्पन्न कर सकते हैं जो my point of view में अधिक स्वीकार्य है।

संबंधित मुद्दे