सवाल क्या मैं LINQ से SQL को गलत समझ रहा हूं .अनुक्रम योग्य ()?


इस कोड पर विचार करें:

var query = db.Table
              .Where(t => SomeCondition(t))
              .AsEnumerable();

int recordCount = query.Count();
int totalSomeNumber = query.Sum();
decimal average = query.Average();

मान लीजिये query चलाने के लिए एक बहुत लंबा समय लगता है। मुझे कुल रिकॉर्ड गिनती मिलनी है SomeNumberवापस आ गया है, और अंत में औसत ले लो। मैंने सोचा कि मेरे पढ़ने पर आधारित है .AsEnumerable() LINQ-to-SQL का उपयोग करके क्वेरी निष्पादित करेगा, फिर LINQ-to-Objects का उपयोग करें Count, Sum, तथा Average। इसके बजाय, जब मैं LINQPad में ऐसा करता हूं, तो मुझे लगता है कि वही क्वेरी तीन बार चलती है। अगर मैं बदलता हूं .AsEnumerable() साथ में .ToList(), यह केवल एक बार पूछताछ हो जाता है।

क्या मुझे कुछ याद आ रहा है AsEnumerable है / करता है?


41
2017-08-02 16:43


मूल


व्यवहार को समझने के लिए एक बहुत ही उपयोगी सवाल है AsEnumerable() - Lijo


जवाब:


कॉलिंग AsEnumerable() क्वेरी निष्पादित नहीं करता है, यह बताता है।

IQueryable इंटरफ़ेस है जो अनुमति देता है LINQ to SQL अपने जादू करने के लिए। IQueryable औजार IEnumerable तो जब आप कॉल करते हैं AsEnumerable(), आप वहां से कॉल किए जाने वाले एक्सटेंशन-विधियों को बदल रहे हैं, यानी से IQueryableके लिए विधि IEnumerable-मात्र (यानी बदल रहा है LINQ to SQL सेवा मेरे LINQ to Objects इस विशेष मामले में)। लेकिन तुम तो नहीं वास्तविक क्वेरी को निष्पादित करना, बस बदलना किस तरह इसे पूरी तरह से निष्पादित किया जा रहा है।

क्वेरी निष्पादन को मजबूर करने के लिए, आपको कॉल करना होगा ToList()


52
2017-08-02 16:49



यह सोचना निश्चित रूप से गलत है कि "कुछ भी वास्तव में नहीं होता"। जबकि AsEnumerable उस समय क्वेरी का मूल्यांकन नहीं करता है जब इसे कहा जाता है निश्चित रूप से एक प्रभाव है क्वेरी पर बुलाए गए कुछ भी का मूल्यांकन LINQ से ऑब्जेक्ट्स का उपयोग करके किया जाएगा, ताकि आप अतिरिक्त तत्वों को क्वेरी पर लिख सकें (दूसरा Where या एक OrderBy या उस प्रकृति का कुछ भी) जो SQL कथन का हिस्सा बन जाएगा। - Adam Robinson
यह वास्तव में एक महान उदाहरण है कि यह क्या करता है और आप इसका उपयोग क्यों करना चाहते हैं: मान लीजिए कि आप एक प्रश्न बना रहे हैं और पहला ब्लॉक समाप्त होता है OrderBy(...), अब प्रकार है IOrderedEnumerable तो बाद में सड़क के नीचे आप संलग्न रख सकते हैं ThenBy(...) और बाद में आप तब भी कह सकते हैं return originalQuery.AsEnumerable() इसे नियमित रूप से वापस करने के लिए IEnumerable - The Muffin Man
मैं ToArray पसंद करता हूं जो वही काम करता है, जब तक कि आपको विशेष रूप से सूची <टी> कार्यान्वयन की आवश्यकता न हो। - Rush Frisby
@rushonerok ToList() तेज़ है, इसलिए जब तक आपकी वस्तुएं लंबे समय तक जीवित न हों, तब तक उपयोग करें ToList और नहीं ToArray, देख stackoverflow.com/a/16323412/691294 - flindeberg


हाँ। सभी कि AsEnumerable करेंगे कारण है Count, Sum, तथा Average कार्यों को क्लाइंट-साइड निष्पादित किया जाना चाहिए (दूसरे शब्दों में, यह क्लाइंट को पूरा परिणाम सेट वापस लाएगा, फिर ग्राहक क्लाइंट को बनाने के बजाय उन योगों को निष्पादित करेगा COUNT()  SUM() तथा AVG() एसक्यूएल में बयान)।


11
2017-08-02 16:46



लेकिन ओपी का मुद्दा यह है कि वह मानता है कि आप जो कहते हैं वह सच है, लेकिन अनुभवजन्य परीक्षण से पता चलता है कि यह नहीं है। - James Curran
-1 यह सच नहीं है। IQueryable INumerable लागू करता है इसलिए AsEnumerable को कॉल एक नो-ऑप है और क्वेरी निष्पादन को मजबूर नहीं करता है। - Justin Niessner
@ जेम्स, जस्टिन: आप गलत समझते हैं। मैने कभी नही कहा कि AsEnumerable() क्वेरी का मूल्यांकन करने का कारण होगा, मैंने कहा कि केवल एक चीज जो इसे जोड़ती है वह है कब कुल मूल्यांकन का मूल्यांकन किया जाता है, वे ग्राहक पक्ष करेंगे (संपूर्ण परिणाम सेट की गणना की जाएगी ग्राहक पर, और समेकित गणना की जाएगी) SQL कथन में अनुवादित होने के बजाय। - Adam Robinson
यह ध्यान रखना अच्छा है कि आप इसका उपयोग करना चाहेंगे AsEnumerable() जब आपके पास है IOrderedEnumerable क्योंकि आपने अपनी क्वेरी के पहले भाग को कुछ प्रकार के ऑर्डरबी के साथ समाप्त कर दिया था। - The Muffin Man
@JustinNiessner यह टिप्पणी सादा तथ्यात्मक गलत है, स्थिर प्रकार कास्टिंग कैसे है कभी ए NOP? यह पूरी निष्पादन योजना को बदलता है ... जो कि बहुत महत्वपूर्ण है क्योंकि LINQ को एक्सटेंशन विधियों (यानी स्थैतिक प्रकार) के रूप में बनाया गया है, विरासत (गतिशील / रनटाइम प्रकार) नहीं। - flindeberg


खैर, आप सही रास्ते पर हैं। समस्या यह है कि ए IQueryable (क्या बयान पहले है AsEnumerable कॉल) भी एक है IEnumerable, ताकि कॉल, असल में, एक एनओपी है। इसे एक विशिष्ट इन-मेमोरी डेटा संरचना (जैसे, ToList()) क्वेरी को मजबूर करने के लिए।


3
2017-08-02 16:50





जस्टिन निसनेर का जवाब पूर्ण है।

मैं बस यहां एक एमएसडीएन स्पष्टीकरण उद्धृत करना चाहता हूं: रिलेशनल डेटा के लिए .NET भाषा-एकीकृत क्वेरी

AsLumerable () ऑपरेटर, ToList () और ToArray () के विपरीत, क्वेरी का निष्पादन नहीं करता है। यह अभी भी स्थगित है। AsEnumerable () ऑपरेटर केवल क्वेरी के स्थिर टाइपिंग को बदलता है, IQueryable को I IEumerable में बदलता है, शेष क्वेरी को स्थानीय रूप से निष्पादित करने के रूप में संकलक को ट्रिक करता है।

मुझे आशा है कि इसका मतलब यह है कि:

IQuery- तरीकों के लिए IQueryable-तरीकों (यानी LINQ से SQL से LINQ तक ऑब्जेक्ट्स में बदलना

एक बार यह LINQ ऑब्जेक्ट्स के बाद हम ऑब्जेक्ट के तरीकों को लागू कर सकते हैं (उदा। तार())। LINQ के बारे में अक्सर पूछे जाने वाले प्रश्नों में से एक के लिए यह स्पष्टीकरण है - LINQ से संस्थाएं विधि 'System.String ToString () को क्यों पहचानती नहीं हैं?

इसके अनुसार ASENUMERABLE - codeblog.jonskeet, AsEnumerable आसान हो सकता है जब:

डेटाबेस में क्वेरी के कुछ पहलुओं, और फिर .NET में थोड़ा अधिक हेरफेर - विशेष रूप से यदि ऐसे पहलू हैं जिन्हें आप मूल रूप से LINQ से SQL (या जो भी प्रदाता आप उपयोग कर रहे हैं) में कार्यान्वित नहीं कर सकते हैं।

यह भी कहता है:

हम जो भी कर रहे हैं वह संकलन-समय प्रकार को अनुक्रमित कर रहा है जो IQueryable से IENumerable तक हमारी क्वेरी के माध्यम से प्रचार कर रहा है - लेकिन इसका मतलब है कि संकलक संख्यात्मक (विधियों को लेना और ऑब्जेक्ट्स में LINQ में निष्पादित करना) के तरीकों का उपयोग करेगा। Queryable में से एक (अभिव्यक्ति पेड़ लेना, और आमतौर पर बाहर प्रक्रिया को निष्पादित)।

अंत में, यह संबंधित प्रश्न भी देखें: IUumerable बनाम IQueryable लौट रहा है


3
2018-06-06 22:08





मैं मानता हूं कि ToList सेनाओं को डेटाबेस से रिकॉर्ड्स लाने के लिए मजबूर करता है। जब आप आगे बढ़ने की गणना करते हैं तो वे डेटाबेस को शामिल करने के बजाय स्मृति वस्तुओं में किए जाते हैं।

वापसी प्रकार को एक गणना के रूप में छोड़ने का अर्थ है कि डेटा तब तक नहीं लाया जाता जब तक कि गणना करने वाले कोड द्वारा इसे कॉल नहीं किया जाता है। मुझे लगता है कि इस पर दस्तक यह है कि डेटाबेस तीन बार मारा जाता है - प्रत्येक गणना के लिए एक और डेटा स्मृति के लिए जारी नहीं है।


1
2017-08-02 16:48