5

मुझे LINQ, द्वारा उत्पन्न एसक्यूएल क्वेरी के साथ कुछ समस्याएं आ रही हैं क्योंकि मेरा पर्यावरण काफी बड़ा है, मैंने एक साधारण उदाहरण दिया जो मेरे प्रतिबिंबित करता है मुसीबत।एंटीटी फ्रेमवर्क 4.1 में LINQ क्वेरी द्वारा जेनरेट किए गए एसक्यूएल को एक से कई संगठनों के साथ अनुकूलित करें

public class ClassA 
{ 
    public int ID { get; set; } 
    public virtual ICollection<ClassB> Children { get; set; } 
} 

public class ClassB 
{ 
    public int ID { get; set; } 
    public string Data { get; set; } 
} 

public class ClassC 
{ 
    public int ID { get; set; } 
    public virtual ICollection<ClassB> Children { get; set; } 
} 

बहुत ही सरल है न:

यह मेरा मॉडल है?

var classA = (from x in db.ClassAs 
      where x.ID == 2 
      select x).First(); 
var classesB = (from b in classA.Children 
       select b.Data).Skip(10).Take(10); 

classesB.ToList(); 

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

(from x in db.ClassAs 
where x.ID == 2 
select x).First() 

हो जाता है:

SELECT TOP (1) 
[Extent1].[ID] AS [ID] 
FROM [dbo].[ClassAs] AS [Extent1] 
WHERE 2 = [Extent1].[ID] 

और:

खैर, यह मेरी क्वेरी है

from b in classA.Children 
select b.Data).Skip(10).Take(10) 

हो जाता है:

SELECT 
[Extent1].[ID] AS [ID], 
[Extent1].[Data] AS [Data], 
[Extent1].[ClassA_ID] AS [ClassA_ID] 
FROM [dbo].[ClassBs] AS [Extent1] 
WHERE ([Extent1].[ClassA_ID] IS NOT NULL) AND ([Extent1].[ClassA_ID] = @EntityKeyValue1) 

काश कि उत्पन्न क्वेरी कुछ इस तरह होगा:

SELECT [Data] AS [Data] 
FROM (SELECT 
     [Data] AS [Data], 
     rownum = ROW_NUMBER() OVER (ORDER BY [B].[ID]) 
     FROM ClassBs AS B , ClassAs AS A 
     WHERE B.ClassA_ID = A.ID 
     AND A.ID = 2) AS T1 
WHERE [t1].rownum BETWEEN 11 AND 20 
ORDER BY [t1].rownum 

बड़ी समस्या है कि क्लास ए है -> कक्षा बी हमेशा एक से अधिक 10k लाइन्स है, और जिस तरह से, ये सभी लाइनें स्मृति में लोड की जा रही हैं, और पेजिंग मेमोरी में बनाई जा रही है, लेकिन मेरी इच्छा है कि यह पेजिंग SQL सर्वर द्वारा की जाएगी।

इसे पूरा करने के तरीके पर कोई विचार?

उत्तर

2

आपको linq-to-entities और linq-to-items के बीच अलग होना चाहिए। यह:

var classA = (from x in db.ClassAs 
       where x.ID == 2 
       select x).First(); 

linq-to-entities है। आप अभिव्यक्ति वृक्ष बनाने के लिए db.ClassAsIQueryable प्रदान कर रहे हैं जो First() पर कॉल करते समय डेटाबेस में SQL के रूप में निष्पादित किया जाएगा। लेकिन यह:

var classesB = (from b in classA.Children 
       select b.Data).Skip(10).Take(10); 

linq-to-items है। क्वेरी स्वयं संग्रह (HashSet) पर परिभाषित की गई है और उस संग्रह पर निष्पादित की गई है। चूंकि आपकी संपत्ति को virtual के रूप में चिह्नित किया गया है, इसलिए ईएफ आपके लिए आलसी लोडिंग ट्रिगर करेगा और उस प्रॉपर्टी में सभी डेटा भरने के लिए आपको स्मृति क्वेरी में निष्पादित करने की अनुमति देगा। यह कभी भी अलग तरीके से काम नहीं करेगा।

आपको अपने संबंधित संपत्ति के लिए डेटाबेस क्वेरी बनाने के लिए आप आलसी लोड करने के बजाय स्पष्ट लोड हो रहा है का उपयोग करना चाहिए चाहते हैं:

db.Entry(classA) 
    .Collection(c => c.Children) 
    .Query() 
    .OrderBy(...) // You must order entities before you can use Skip and Take 
    .Skip(10) 
    .Take(10) 
    .Load(); 

var classesB = classA.Children; 
+0

धन्यवाद! इसने काम कर दिया! –

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