2012-03-12 13 views
5

मैं संस्थाओं क्वेरी के लिए निम्न LINQ जो कई सबक्वेरी है कुछ कुल डेटा प्राप्त करने के लिए है के लिए एक ही शामिलRefactor LINQ/संस्थाओं कई सबक्वेरी साथ क्वेरी

var systems = from s in db.Systems 
       orderby s.Name 
       select new SystemSummary 
       { 
        Id = s.Id, 
        Code = s.Code, 
        Name = s.Name, 
        LastException = (
         from a in s.Applications 
         from e in a.Summaries 
         select e.CreationDate 
       ).Max(), 
        TodaysExceptions = (
         from a in s.Applications 
         from e in a.Summaries 
         where e.CreationDate >= today && e.CreationDate < tomorrow 
         select e 
       ).Count(), 
        /* SNIP - 10-15 more subqueries */        
       }; 

मैं क्वेरी अप छोटा सबक्वेरी के 2 , लेकिन उनमें से लगभग 10-15 अधिक हो सकते हैं। क्या कोई तरीका है कि मैं कोड को साफ करने के लिए क्वेरी को दोबारा कर सकता हूं? मैं प्रदर्शन में वृद्धि की तलाश नहीं कर रहा हूं। मैं अभी भी यह सुनिश्चित कर रहा हूं कि यह डेटाबेस के लिए एक ही कॉल है, जबकि यह सुनिश्चित कर रहा है कि सबकुछ को अलग-अलग विधियों में डालकर कोड को साफ़ करना चाहते हैं। क्या यह संभव है?

+0

यदि आप क्लीनर कोड चाहते हैं, तो आप अपने डेटाबेस में संग्रहीत प्रक्रिया बनाने पर विचार करना चाहेंगे – Mathieu

+0

@ मैथ्यूयू क्या यह एकमात्र तरीका है, हालांकि? – Dismissile

उत्तर

2

मैं बस (आपकी मूल क्वेरी में let कीवर्ड का उपयोग करके) कुछ इस तरह से उसकी लम्बाई कम से कम की पेशकश कर सकते हैं:

subQuery.Count(e=>e.CreationDate >= today && e.CreationDate < tomorrow); 

subQuery.max(e=>e.CreationDate); 

वास्तव में:

var subQuery = from a in s.Applications 
        from e in a.Summaries 
        select e; 

इसके अलावा, आप जैसे कुछ refactors हो सकता है डॉट नोटेशन का उपयोग करें और अतिरिक्त where खंड के बजाय अपनी क्वेरी को संबंधित फ़ंक्शन पर ले जाएं।

और अपने प्रश्न में subQuery का उपयोग करें:

  from s in db.Systems 
      orderby s.Name 
      let subQuery = from a in s.Applications 
        from e in a.Summaries 
        select e 
      select new SystemSummary 
      { 
       Id = s.Id, 
       Code = s.Code, 
       Name = s.Name, 
       LastException = subQuery.max(e=>e.CreationDate), 
       TodaysExceptions = subQuery.Count(e=>e.CreationDate >= today 
              && e.CreationDate < tomorrow), 
       /* SNIP - 10-15 more subqueries */        
      }; 

यह अभी भी एक db से कॉल है।

+0

@ डिस्मिसाइल, मुझे याद आया, मैं जवाब संपादित कर दूंगा, आप अपनी क्वेरी में इस तरीके को अनुकरण करने के लिए 'let' का उपयोग कर सकते हैं। –

+0

मुझे यह दृष्टिकोण पसंद है। – Dismissile

+0

इस मदद की आशा है, अच्छा भी अपनी टिप्पणी देखें :) –

0

आपकी क्वेरी को कई तरीकों से अलग करने में वास्तव में कोई समस्या नहीं है। यद्यपि कुछ स्थितियां हैं।

सुनिश्चित करें कि आपकी क्वेरी IEumerable है। यह डिफ़ॉल्ट रूप से है।

IENumerable यह सुनिश्चित करता है कि क्वेरी चर में संग्रहीत है, लेकिन निष्पादित नहीं है। कंपाइलर आपके प्रश्नों को रन टाइम पर अनुकूलित करता है।

त्वरित और गंदे उदाहरण:

private MyContext context = new MyContext() 
private IEnumerable<User> getUser(Guid userID) 
{ 
    return context.User.Where(c => c.ID == userID); 
} 

private void evaluateUser() 
{ 
    bool isUserActive getUser().Any(c => c.IsActive) 
} 

आप देख सकते हैं कि क्वेरी दो तरीकों में है। डीबी को अभी भी केवल एक कॉल है क्योंकि एक आईनेमेरेबल क्वेरी को स्टोर करता है न कि परिणाम। क्वेरी केवल तभी निष्पादित की जाती है जब आवश्यक हो।

+2

मुझे लगता है कि आपका मतलब IQueryable है, IENumerable नहीं।IENumerable यह क्वेरी को इन-मेमोरी ऑब्जेक्ट में परिवर्तित कर देगा। –

0

आप क्वेरी में स्थानीय "चर" बनाने के लिए let कीवर्ड का उपयोग करने पर विचार करना चाहेंगे (यह अंत में आपकी उपक्वियर बनता है)। उदाहरण के लिए:

var systems = from s in db.Systems 
       orderby s.Name 
       let lastException = (from a in s.Applications from e in a.Summaries select e.CreationDate).Max() 
       ... 

एक अन्य विकल्प आप संभवतः सही बल्ले से दूर विभिन्न संघों से एक सबक्वेरी बनाते हैं, और उन तत्वों के साथ काम कर रहा है कर सकता है।

var systems = from s in db.Systems 
       orderby s.Name 
       from summaries in 
        (from ta in s.Applications 
        from te in ta.Summaries 
        ... 
        select { APPS = ta, SUMMS = te ,/*anything else you want*/ }) 
       let lastExpire = (from summaries select SUMMS.CreationDate).Max() 

नरक, तुम भी सिर्फ दूसरे उदाहरण में बाहर जाने छोड़ सकता है और बस अपने अंतिम चयन में summaries संस्थाओं का उपयोग करें। आपको यह सुनिश्चित करने के लिए थोड़ा सा खेलना पड़ सकता है कि आपको मूल्यों का कोई डुप्लिकेशंस नहीं मिलता है, लेकिन कम से कम इस तरह से आप हर बार अपनी सबक्वायरी को फिर से लिखने के बजाय अपने summaries के खिलाफ सीधे चयन कर सकते हैं।

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