2011-09-09 8 views
14

मेरे पास एक क्वेरी है जो SQL के लिए पूरी तरह से अनुवाद योग्य है। अज्ञात कारणों से LINQ ने .NET (डेटाबेस में नहीं) में निष्पादित करने के लिए अंतिम Select() का निर्णय लिया है, जो डेटाबेस के विरुद्ध बहुत से अतिरिक्त SQL क्वेरी (प्रत्येक आइटम प्रति) चलाने का कारण बनता है।डेटाबेस में पूरी क्वेरी का मूल्यांकन करने के लिए LINQ से SQL को कैसे बल देना है?

वास्तव में, मैं एक 'अजीब' जिस तरह से एसक्यूएल करने के लिए पूर्ण अनुवाद के लिए मजबूर करने के लिए मिला:

MainCategories.Select(e => new 
{ 
    PlacementId = e.CatalogPlacementId, 
    Translation = Translations.Select(t => new 
    { 
     Name = t.Name, 
     // ... 
    }).FirstOrDefault() 
}) 
:

मैं एक प्रश्न है (यह एक बहुत सरलीकृत संस्करण है, जो अभी भी रूप में की उम्मीद काम नहीं करता है)

01: अगर मैं एक और Select() जो सिर्फ प्रतियां सभी सदस्यों संलग्न,

SELECT [t0].[CatalogPlacementId] AS [PlacementId] 
FROM [dbo].[MainCategories] AS [t0] 

SELECT TOP (1) [t0].[Name] 
FROM [dbo].[Translations] AS [t0] 

SELECT TOP (1) [t0].[Name] 
FROM [dbo].[Translations] AS [t0] 

... 

हालांकि:

यह होगा एसक्यूएल प्रश्नों का एक बहुत उत्पन्न करता है

.Select(e => new 
{ 
    PlacementId = e.PlacementId, 
    Translation = new 
    { 
     Name = e.Translation.Name, 
     // ... 
    } 
}) 

यह एक एसक्यूएल बयान में यह संकलन होगा:

SELECT [t0].[CatalogPlacementId] AS [PlacementId], (
    SELECT [t2].[Name] 
    FROM (
     SELECT TOP (1) [t1].[Name] 
     FROM [dbo].[Translations] AS [t1] 
     ) AS [t2] 
    ) AS [Name] 
FROM [dbo].[MainCategories] AS [t0] 

कोई सुराग क्यों? LINQ से SQL को एक और क्वेरी जेनरेट करने के लिए मजबूर कैसे करें (दूसरी प्रतिलिपि Select() के बिना)?

नोट: मैंने इसे वास्तव में सरल बनाने के लिए क्वेरी में अपडेट किया है।

पुनश्च: केवल, विचार मैं पोस्ट-प्रक्रिया/समान पैटर्न के साथ प्रश्नों को बदलने के लिए (एक और Select() जोड़ने के लिए) है।

+2

कृपया MyQuery() दिखाएं। –

उत्तर

6

जब आप पर MyQuery पर कॉल करते हैं, तो आप उस बिंदु पर क्वेरी निष्पादित कर रहे हैं जो क्लाइंट में परिणाम लोड कर रहा है।

सिंगलऑर्डडिल्ट IEnumerable<T> देता है जो अब IQueryable<T> नहीं है। आपने इस बिंदु पर इसे मजबूर कर दिया है जो क्लाइंट पर आगे की प्रक्रिया करेगा - यह अब एसक्यूएल संरचना नहीं कर सकता है।

+0

यह क्यों काम करता है, जब मैं एक और 'चयन() 'जोड़ता हूं? 'सिंगलऑर्डफॉल्ट' किसी अन्य क्वेरी के अंदर घोंसला है। –

+0

उस बारे में 100% निश्चित नहीं है। सिंगलऑर्डडिल्ट को यह निर्धारित करने के लिए क्वेरी का मूल्यांकन करना होगा कि परिणाम सेट में एक रिकॉर्ड है या नहीं। आपके पहले मामले में, ToArray मुख्य श्रेणियों के माध्यम से पुनरावृत्त करने जा रहा है और अनुवाद टुकड़े के लिए सिंगलऑर्डडिल्ट निष्पादित कर रहा है (जो घोंसला है ताकि आप प्रत्येक श्रेणी के लिए क्वेरी को फिर से शुरू कर सकें)। आप कैसे जानते हैं कि SELECT की तीसरी परत जोड़ना एक प्रश्न पूछता है? –

+0

IEERumerable पर IQueryable को जोड़ने के बारे में मेरा जोड़ा गया नोट देखें। –

1

पूरी तरह से सुनिश्चित नहीं है कि क्या हो रहा है, लेकिन मुझे लगता है कि आपने यह प्रश्न सुंदर 'अजीब' लिखा है। अपने लक्ष्य प्रकार के

 var q = from e in MainCategories 
       let t = Translations.Where(t => t.Name == "MainCategory" 
        && t.RowKey == e.Id 
        && t.Language.Code == "en-US").SingleOrDefault() 
       select new TranslatedEntity<Category> 
          { 
           Entity = e, 
           Translation = new TranslationDef 
               { 
                Language = t.Language.Code, 
                Name = t.Name, 
                Xml = t.Xml 
               } 
          }; 

मैं हमेशा select भाग से (datasources के चयन) from हिस्सा अलग करने की कोशिश (प्रक्षेपण मैं यह भी आसान लगता है: मैं इस तरह यह लिखते थे, और संदेह है कि यह काम करेगा।/पढ़ने के लिए समझते हैं, और यह आम तौर पर भी सबसे LINQ प्रदाताओं के साथ बेहतर काम करता है

+0

हां, लेकिन मेरी क्वेरी हाथ से लिखी नहीं बल्कि बल्कि जेनरेट की गई है। (मैंने अभी भी वास्तव में सरलीकृत उदाहरण पोस्ट किया है जो अभी भी काम नहीं कर रहा है :) –

1

आप क्वेरी के रूप में वांछित परिणाम प्राप्त करने के लिए इस प्रकार लिख सकते हैं:। जहां तक ​​मुझे पता है हूँ

MainCategories.Select(e => new 
{ 
    PlacementId = e.CatalogPlacementId, 
    TranslationName = Translations.FirstOrDefault().Name, 
}) 

, यह कारण है LINQ क्वेरी को कैसे प्रोजेक्ट करता है। मैं पतला हूं k जब यह nested Select देखता है, तो यह कई उप-प्रश्नों में प्रोजेक्ट नहीं करेगा, जैसा कि आवश्यक है, आईआईआरसी के रूप में आप SQL में उप-क्वेरी से एकाधिक रिटर्न कॉलम का उपयोग नहीं कर सकते हैं, इसलिए LINQ इसे बदलता है एक क्वेरी-प्रति-पंक्ति। कॉलम एक्सेसर के साथ FirstOrDefault एसक्यूएल में क्या होगा इसके लिए सीधा अनुवाद प्रतीत होता है और इसलिए LINQ-SQL जानता है कि यह उप-क्वेरी लिख सकता है।

दूसरा Select इस क्वेरी को प्रोजेक्ट करना चाहिए जैसा मैंने ऊपर लिखा है। एक परावर्तक में खोदने के बिना पुष्टि करना मुश्किल होगा। आम तौर पर, अगर मुझे कई कॉलम चुनने की ज़रूरत है, तो मैं नीचे let कथन का उपयोग करूंगा:

from e in MainCategories 
let translation = Translations.FirstOrDefault() 
select new 
{ 
    PlacementId = e.CatalogPlacementId, 
    Translation = new { 
     translation.Name, 
    } 
}) 
+0

मूल क्वेरी अधिक जटिल है। यह हाथ से लिखा नहीं है बल्कि कई कार्यों द्वारा उत्पन्न किया गया है। मैं सिर्फ क्वेरी को फिर से लिख नहीं सकता। केवल मैं जो कर सकता हूं वह एक और 'चयन()' जोड़ना है जो 'चलो' वास्तव में कर रहा है। –

+1

क्या आप अपमानजनक क्वेरी को दोबारा लिख ​​नहीं पाएंगे क्योंकि खराब प्रदर्शन के साथ एसक्यूएल का उत्पादन होता है, और कोई अन्य कॉलर संभावित रूप से आपके आवेदन में भारी बाधा उत्पन्न कर सकता है? उत्पादन एक ही बेहतर है, मोटे तौर पर एक बेहतर इनपुट। मेरा और आपकी क्वेरी के बीच एक सूक्ष्म अंतर है। – Mig

+0

जैसा कि मैंने उल्लेख किया है कि परिणामी क्वेरी हाथ से लिखी नहीं गई है बल्कि LINQ अभिव्यक्ति वृक्ष परिवर्तन कार्यों द्वारा उत्पन्न की गई है, केवल एक ही तरीका है जिसे मैंने पाया है 'चयन()' क्वेरी या LINQ अभिव्यक्ति वृक्ष को बदलना है। –