2011-09-30 16 views
23

कृपया कोड की यह लाइन देखें। यह संग्रहीत प्रक्रिया का आविष्कार है, जो ObjectResult<long?> देता है। आदेश में लंबे समय के मूल्यों को निकालने के लिए मैं चुनें कहा:.NET इकाई फ्रेमवर्क - आईनेमेरेबल वीएस। IQueryable

dbContext.FindCoursesWithKeywords(keywords).Select(l => l.Value); 

IntelliSense के आधार पर इस का चयन देता है IEnumerable<long>

मुझे यकीन नहीं है कि मैंने इसे कहीं पढ़ा है या शायद इस धारणा के लिए उपयोग किया गया है - मैंने हमेशा सोचा था कि जब ईएफ एपीआई IEnumerable (और IQueryable नहीं) तो इसका मतलब है कि परिणाम भौतिक हो गए हैं। मतलब वे डेटाबेस से खींच लिया गया है।

मुझे पता चला कि मैं गलत था (या शायद यह एक बग है?)। मैं त्रुटि

मूल रूप से "क्योंकि वहाँ अन्य थ्रेड सत्र में चल रहे हैं नए लेन-देन की अनुमति नहीं है", यह त्रुटि आपको बताता है कि आप जबकि परिवर्तनों को सहेजने की कोशिश कर रहे हो रही है डीबी रीडर अभी भी रिकॉर्ड पढ़ रहा है।

अंततः मैं इसे द्वारा (क्या मैं एक लंबे शॉट माना जाता है) हल और IEnumerable<long> ...

तो अमल में लाना करने के लिए ToArray() कॉल जोड़ा - लब्बोलुआब यह है - मैं उम्मीद करनी चाहिए एफई से IEnumerable परिणाम है कि हेवन परिणाम को रोकने के लिए अभी तक भौतिक नहीं है? यदि हां तो क्या यह जानने का कोई तरीका है कि IEnumerable भौतिक हो गया है या नहीं?

धन्यवाद और क्षमा याचना अगर यह उन 'duhhh द्वारा पूछे गये सवालों में से एक है ... :)

+0

मैं वहाँ कुछ भी विशेष रूप से एफई के लिए दस्तावेज है कि अगर यकीन नहीं है, लेकिन सामान्य में Linq, के लिए एक 'IEnumerable ' है और नहीं "materialized" एक 'IQueryable ' से - दोनों आम तौर पर आस्थगित निष्पादन उपयोग करने के लिए माना जाता है। –

+0

@Damien_The_Unbeliever: हालांकि, मुझे लगता है कि ऑब्जेक्ट रेसल्ट फ़ंक्शन कहलाए जाने पर हमेशा निष्पादित होगा ... (इस मामले में FindCoursesWithKeywords) –

उत्तर

27

IQueryable का उपयोग तब किया जाता है जब आप लिंक-टू-एंटिटीज का उपयोग कर रहे हैं = आप अपने एप्लिकेशन में घोषणात्मक LINQ क्वेरी बना रहे हैं जिसका अर्थ LINQ प्रदाता द्वारा एसक्यूएल के रूप में किया जाएगा और सर्वर पर निष्पादित किया जाएगा। एक बार क्वेरी निष्पादित हो जाने पर (पुनरावृत्त) यह IENumerable बन जाएगा और वस्तुओं को पुनरावृत्ति के लिए आवश्यकतानुसार भौतिक रूप दिया जाएगा = तुरंत नहीं।

एक बार जब आप संग्रहीत प्रक्रिया को कॉल करते हैं तो आप लिंक-टू-एंटिटीज का उपयोग नहीं कर रहे हैं क्योंकि आपके आवेदन में कोई घोषणात्मक क्वेरी नहीं है। क्वेरी/एसक्यूएल डेटाबेस सर्वर पर पहले से मौजूद है और आप इसे अभी आमंत्रित कर रहे हैं। यह IEnumerable लौटाएगा लेकिन फिर से यह तुरंत सभी परिणामों को पूरा नहीं करेगा। परिणाम पुनरावृत्त के रूप में पूरा किया जाएगा। जब आप ऑब्जेक्ट लाने के लिए स्पष्ट रूप से पूछते हैं तो यह डेटाबेस कर्सर/या .NET डेटा रीडर का सिद्धांत है।

foreach (var keyword in dbContext.FindCoursesWithKeywords(keywords) 
           .Select(l => l.Value)) 
{ 
    ... 
} 

आप पाठ्यक्रम एक के बाद एक फ़ेच कर रहे हैं:

तो अगर आप कुछ इस तरह फोन (। Btw क्यों पूरे पाठ्यक्रम लोड करने के लिए अगर आप केवल कीवर्ड में रुचि रखते हैं?)। जब तक आप लूप को पूरा या तोड़ नहीं देते, तब तक रिकॉर्ड प्राप्त करने के लिए आपका डेटा रीडर खोला जाता है।

आप के बजाय इस कॉल करते हैं:

foreach (var keyword in dbContext.FindCoursesWithKeywords(keywords) 
           .ToList() // or ToArray 
           .Select(l => l.Value)) 
{ 
    ... 
} 

आप तुरंत सभी परिणाम अमल में लाना करने के लिए क्वेरी के लिए बाध्य करेगा और पाश खोला डेटाबेस पाठक के बजाय स्मृति में संग्रह पर प्रदर्शन करेंगे।

IEnumerable और IQueryable के बीच

अंतर रास्ता कैसे डेटा लाई जाती हैं, क्योंकि IQueryableIEnumerable है में नहीं है। अंतर समर्थन में है (कुछ इन इंटरफेस को लागू करना चाहिए)।

+0

हाय, इस स्पष्टीकरण के लिए धन्यवाद!इसलिए चूंकि यह एक संग्रहित प्रो है, इसलिए यह एक IQueryable वापस नहीं करेगा, क्योंकि यह क्वेरी की सभी सुविधाओं का समर्थन नहीं करता है, है ना? (बीटीडब्ल्यू, मैं पाठ्यक्रम नहीं ले रहा पाठ्यक्रम नहीं) :) – justabuzz

10

एक IEnumerable<T> पर कार्य करना मतलब है कि सभी आगे संचालन सी # कोड है, यानी LINQ करने वाली वस्तुओं में क्या होगा। इसका मतलब यह नहीं है कि क्वेरी पहले ही निष्पादित हो चुकी है।

एक बार जब आप linq-to-items में अपग्रेड कर लेते हैं तो इस बिंदु पर छोड़े गए सभी डेटा को डेटाबेस से लाया जाना चाहिए और .net पर भेजा जाना चाहिए। यह प्रदर्शन को काफी हद तक खराब कर सकता है (उदाहरण के लिए डेटाबेस इंडेक्स का उपयोग linq-to-objects द्वारा नहीं किया जाएगा), लेकिन दूसरी तरफ linq-to-items अधिक लचीला है, क्योंकि यह मनमाने ढंग से C# कोड को निष्पादित करने के बजाय निष्पादित कर सकता है आपका linq प्रदाता SQL में अनुवाद कर सकते हैं।

IEnumerable<T> दोनों एक स्थगित क्वेरी या पहले से ही भौतिक डेटा हो सकता है। मानक लिनक ऑपरेटरों को आम तौर पर स्थगित कर दिया जाता है, और ToArray()/ToList() हमेशा भौतिककृत होते हैं।

+0

इस भेद के लिए धन्यवाद! तो क्या मुझे कुछ पता होना चाहिए? क्या कोई प्रभाव या गठिया हैं? चीयर्स! – justabuzz

+0

सबसे स्पष्ट गॉचा यह है कि 'आईनेमेरेबल ' में गिरावट प्रदर्शन को काफी कम कर सकती है। कल्पना करें कि आप क्वेरी की शुरुआत में गिरावट करते हैं, तो संभव है कि स्पीडअप के लिए डेटाबेस पर इंडेक्स का उपयोग कर सर्वर पर SQL का उपयोग करके फ़िल्टर करने के बजाय पूरी तालिका को लाने की आवश्यकता है। तो उस बिंदु पर जहां आप 'IENumerable 'पर अपग्रेड करते हैं, आप जितना संभव हो उतना कम आइटम रखना चाहते हैं। – CodesInChaos

+0

यह भी सुनिश्चित नहीं है कि यह सही है। आगे पढ़ने मैंने किया + दूसरा जवाब यहां एक समान बात कहता है - IENumerable तब भी इसे तब तक पूरा नहीं कर सकता जब आप इसे पुन: सक्रिय करते हैं। अगर मैं समझता हूं कि यह सही है क्योंकि जब आप एक संग्रहित प्रो को निष्पादित करते हैं तो आपको पूर्ण IQueryable मिलता है, क्योंकि यह पूर्ण क्वेरी करने योग्य ऑब्जेक्ट नहीं है। समझ में आता है? :) – justabuzz

-5

आईनेमरेबल: LINQ से ऑब्जेक्ट और LINQ से XML तक।

IQueryable: LINQ

+0

IQueryable एक ऐसा प्रकार है जिसे अभी तक निष्पादित नहीं किया गया है। असल में यह "क्वेरी" है। http://msdn.microsoft.com/en-us/library/system.linq.iqueryable(v=vs.100).ASPX विरूद्ध रूप से LINQ से SQL, या Linq से कुछ भी करने के लिए कुछ भी नहीं है। यह किसी भी प्रकार के डेटा प्रदाता तक पहुंच प्रदान करने के लिए एक इंटरफ़ेस है। – Tony

0

IEnumerable तक हाइड्रेट नहीं होंगे materialized SQL करने के लिए। यदि संग्रहीत प्रक्रिया को कॉल करना है तो मुझे लगता है कि कोई और फ़िल्टर आवश्यक नहीं है, मेरा मतलब है कि आप लौटाए गए डेटा के वांछित सबसेट का उत्पादन करने के लिए संग्रहीत प्रक्रिया में पैरामीटर भेजते हैं। एक संग्रहीत प्रक्रिया से बंधे IENumerable ठीक है। हालांकि यदि आप किसी तालिका की संपूर्ण सामग्री प्राप्त कर रहे हैं, तो एप्लिकेशन में फ़िल्टर करना आपके पास एक रणनीति होनी चाहिए। पसंद है, तालिका के IENumerable ToList() नहीं, आप सभी पंक्तियों को पूरा करेंगे। कभी-कभी यह स्मृति अपवाद से बाहर हो जाएगा। बिना कारण के मेमोरी का उपभोग करें। संदर्भ के खिलाफ IQueryable का उपयोग करें, इस तरह आप डेटा स्रोत पर तालिका फ़िल्टर कर सकते हैं, न कि एप्लिकेशन में। जवाब में, आपको इसे पूरा करना होगा। IENumerable एक इंटरफ़ेस है, केवल भौतिककरण यह इसके प्रकार को "प्रारंभ" करेगा और मेरी समझ में कुछ उत्पन्न करेगा।

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