7

पर विचार करें इन काल्पनिक इकाई वस्तुओं:निकाला जा रहा है का चयन एन 1 .Include बिना

public class Consumer 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
    public bool NeedsProcessed { get; set; } 
    public virtual IList<Purchase> Purchases { get; set; } //virtual so EF can lazy-load 
} 

public class Purchase 
{ 
    public int Id { get; set; } 
    public decimal TotalCost { get; set; } 
    public int ConsumerId { get; set; } 
} 

अब मान लीजिए कि मैं इस कोड को चलाने के लिए चाहते हैं:

var consumers = Consumers.Where(consumer => consumer.NeedsProcessed); 

//assume that ProcessConsumers accesses the Consumer.Purchases property 
SomeExternalServiceICannotModify.ProcessConsumers(consumers); 

डिफ़ॉल्ट रूप से यह एन चयन से भुगतना होगा + ProcessConsumers विधि के अंदर 1। जब यह उपभोक्ताओं विश्लेषण करता है यह एक प्रश्न ट्रिगर किया जाएगा तो यह 1. द्वारा प्रत्येक खरीद संग्रह 1 हड़पने देंगे इस समस्या का समाधान मानक जोड़ने के लिए एक में शामिल हो सकता है,:,

var consumers = Consumers.Include("Purchases").Where(consumer => consumer.NeedsProcessed); 

//assume that ProcessConsumers accesses the Consumer.Purchases property 
SomeExternalServiceICannotModify.ProcessConsumers(consumers); 

कि कई मामलों में ठीक काम करता है लेकिन कुछ जटिल मामलों में, एक परिमाण परिमाण के आदेश द्वारा प्रदर्शन को पूरी तरह नष्ट कर सकता है। यह संभव है इस तरह कुछ करने के लिए है:।

  1. मेरी उपभोक्ताओं, वर उपभोक्ताओं पकड़ो = _entityContext.Consumers.Where (...) ToList()
  2. मेरी खरीदारी, वर खरीद = _entityContext.Purchases पकड़ो। कहां (...)। ToList()
  3. उपभोक्ता को हाइड्रेट करें। खरीदारी संग्रह मैन्युअल रूप से खरीदे गए खरीदारियों से खरीदता है। फिर जब मैं इसे प्रोसेस कंसुमर्स को पास करता हूं तो यह अधिक डीबी प्रश्नों को ट्रिगर नहीं करेगा।

मैं कैसे # 3 करने के लिए यकीन नहीं है। यदि आप किसी उपभोक्ता तक पहुंचने का प्रयास करते हैं। खरीद संग्रह जो आलसी लोड को ट्रिगर करेगा (और इस प्रकार एन + 1 का चयन करें)। शायद मुझे उपभोक्ताओं को उचित प्रकार (ईएफ प्रॉक्सी प्रकार के बजाय) में डालना होगा और फिर संग्रह लोड करना होगा? कुछ इस तरह:

foreach (var consumer in Consumers) 
{ 
    //since the EF proxy overrides the Purchases property, this doesn't really work, I'm trying to figure out what would 
    ((Consumer)consumer).Purchases = purchases.Where(x => x.ConsumerId = consumer.ConsumerId).ToList(); 
} 

संपादित करें: मैं है एक सा फिर से लिखा उदाहरण उम्मीद है कि और अधिक स्पष्ट रूप मुद्दा प्रकट करने के लिए।

+1

आईआईआरसी ईएफ स्वचालित रूप से संग्रह को हाइड्रेट कर देगा, इसलिए # 3 मैन्युअल रूप से नहीं किया जाना चाहिए। – jeroenh

+1

आपकी पहली क्वेरी को एक एकल SQL कथन के रूप में निष्पादित करना चाहिए। क्या आप कई डीबी कॉल देख रहे हैं? –

+0

@ निकोलस, आप सही हैं, मैंने इसे एन + 1 का चयन करने के लिए उदाहरण अपडेट किया है। यह एक बहुत ही सरल संकुचित उदाहरण है, पूरे प्रश्न को पढ़ें और यह समझने की कोशिश करें कि मैं वास्तव में क्या पूछ रहा हूं। वास्तविक उदाहरण जहां शामिल हैं अपर्याप्त हैं नाटकीय रूप से अधिक जटिल हैं और एक SO प्रश्न के अंदर उचित नहीं है। – manu08

उत्तर

0

एफई, आप के लिए consumer.Purchases संग्रह से स्थापित हो जाएगा अगर आप एक ही संदर्भ का उपयोग दोनों संग्रह लाने के लिए:

List<Consumer> consumers = null; 
using (var ctx = new XXXEntities()) 
{ 
    consumers = ctx.Consumers.Where(...).ToList(); 

    // EF will populate consumers.Purchases when it loads these objects 
    ctx.Purchases.Where(...).ToList(); 
} 

// the Purchase objects are now in the consumer.Purchases collections 
var sum = consumers.Sum(c => c.Purchases.Sum(p => p.TotalCost)); 

संपादित करें:

यह सिर्फ 2 db कॉल में परिणाम है: 1 पाने के लिए Consumers और 1 का संग्रह Purchases का संग्रह प्राप्त करने के लिए।

ईएफ प्रत्येक Purchase रिकॉर्ड वापस देखेगा और Purchase.ConsumerId से संबंधित Consumer रिकॉर्ड देखेंगे। इसके बाद Purchase ऑब्जेक्ट को आपके लिए Consumer.Purchases संग्रह में जोड़ दिया जाएगा।


विकल्प 2:

अगर किसी कारण आप विभिन्न संदर्भों से दो सूचियों को लाने के लिए और फिर उन्हें लिंक, मैं Consumer वर्ग के लिए एक और संपत्ति जोड़ना होगा चाहते हैं:

partial class Consumer 
{ 
    public List<Purchase> UI_Purchases { get; set; } 
} 

फिर आप इस संपत्ति को Purchases संग्रह से सेट कर सकते हैं और इसे अपने यूआई में उपयोग कर सकते हैं।

+0

विकल्प 1 मेरे ऊपर जो कुछ है, उसका पुन: विश्राम है, है ना? यह अभी भी एन + 1 का चयन करेगा। विकल्प 2 उचित है, लेकिन यह वास्तव में मेरे मामले के लिए काम नहीं करेगा। मैं विस्तृत करने के लिए अपना मूल प्रश्न अपडेट करूंगा। – manu08

+0

नहीं, इसके परिणामस्वरूप केवल 2 डीबी कॉल होते हैं। मैंने अपने जवाब में और स्पष्टीकरण जोड़ा है। –

0

पकड़ो मेरी उपभोक्ताओं

var consumers = _entityContext.Consumers 
           .Where(consumer => consumer.Id > 1000) 
           .ToList(); 

मेरी खरीद पकड़ो

var purchases = consumers.Select(x => new { 
             Id = x.Id, 
             IList<Purchases> Purchases = x.Purchases   
             }) 
         .ToList() 
         .GroupBy(x => x.Id) 
         .Select(x => x.Aggregate((merged, next) => merged.Merge(next))) 
         .ToList(); 

उपभोक्ता को हाइड्रेट करें। खरीद संग्रह मैन्युअल रूप से खरीदारियों से खरीदता है जो मैंने पहले से ही स्मृति में लोड किया है। एक विशेष के बजाय एक प्रक्षेपण वापस लौट कर अनिवार्य रूप से -

for(int i = 0; i < costumers.Lenght; i++) 
    costumers[i].Purchases = purchases[i]; 
+0

मेरा मानना ​​है कि बाएं आधे उपभोक्ताओं [i]। खरीद = खरीद [i], आपके लिए खरीदारियों को लोड करने का प्रयास करने के लिए ईएफ को ट्रिगर करेगा। तो आप आलसी लोड को ट्रिगर करेंगे और फिर इसे लिख लेंगे। – manu08

+0

आप चरण 3 से पहले ऑब्जेक्ट ग्राफ़ को संदर्भ से अलग कर सकते हैं, या आलसी लोडिंग क्षमता को अक्षम कर सकते हैं। –

+0

@MortenMertner मेरे मामले में मैं आलसी लोडिंग को पूरी तरह अक्षम नहीं कर सकता क्योंकि मुझे बाद में आलसी लोड होने की अन्य चीजों की आवश्यकता है। मैं ऑब्जेक्ट को अलग करने, मैन्युअल रूप से लोड करने, फिर ऑब्जेक्ट को दोबारा जोड़ने के साथ खेलूँगा। विचार के लिए धन्यवाद। – manu08

0

यह आप डेटाबेस पर काम कर रही द्वारा भर के कई-roundtrips या अक्षम क्वेरी पीढ़ी समस्या काम करने के लिए संभव नहीं होगा इकाई, जैसा कि नीचे बताया:

var query = from c in db.Consumers 
      where c.Id > 1000 
      select new { Consumer = c, Total = c.Purchases.Sum(p => p.TotalCost) }; 
var total = query.Sum(cp => cp.Total); 

मैं किसी भी तरह से एक एफई विशेषज्ञ नहीं हूँ, इसलिए मुझे माफ कर दो, तो इस तकनीक को उचित नहीं है।

+0

यह तकनीक प्रदूषित उदाहरण के लिए ठीक है, लेकिन मैं आपको यह मानने के लिए कह रहा हूं कि यह अधिक जटिल है (उदाहरण के लिए, आपको उपभोक्ताओं और उनकी खरीद के साथ कई अन्य सामान करने की आवश्यकता है, ताकि आप पूरे ऑब्जेक्ट ग्राफ को स्मृति में चाहते हों)। – manu08

+0

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

1

यदि मैं सही ढंग से समझ रहा हूं, तो आप उपभोक्ताओं के एक फ़िल्टर किए गए सबसेट को प्रत्येक क्वेरी में फ़िल्टर किए गए सबसेट के साथ लोड करना चाहते हैं। यदि यह सही नहीं है, तो कृपया अपने इरादे की मेरी समझ को क्षमा करें।

var consumersAndPurchases = db.Consumers.Where(...) 
    .Select(c => new { 
     Consumer = c, 
     RelevantPurchases = c.Purchases.Where(...) 
    }) 
    .AsNoTracking() 
    .ToList(); // loads in 1 query 

// this should be OK because we did AsNoTracking() 
consumersAndPurchases.ForEach(t => t.Consumer.Purchases = t.RelevantPurchases); 

CannotModify.Process(consumersAndPurchases.Select(t => t.Consumer)); 

ध्यान रहे कि यदि प्रक्रिया समारोह उपभोक्ता वस्तु को संशोधित करने और फिर उन परिवर्तनों को वापस डेटाबेस के लिए प्रतिबद्ध करने के लिए उम्मीद कर रही है काम नहीं करेगा: यदि यह सही है, तो आप की तरह कुछ कर सकता है।

+0

यह परिवर्तन ट्रैकिंग को रोक देगा, लेकिन मेरा मानना ​​है कि t.Consumer.Purchases अभी भी आलसी लोड को ट्रिगर करेगा, इससे पहले कि टी। प्रासंगिक खरीद। – manu08

+0

मुझे आश्चर्य है कि ऐसा होगा। हालांकि, यदि यह हो रहा है, तो आप जोड़ सकते हैं (ToList() कॉल के बाद): चयन करें (टी => नया उपभोक्ता {/ * टी। उपभोक्ता * /, खरीद = टी। प्रासंगिक खरीद} से सभी प्रासंगिक फ़ील्ड कॉपी करें।) सूची()। यह प्रभावी रूप से गैर-ईएफ-प्रॉक्सी ऑब्जेक्ट्स में सब कुछ मैप करना चाहिए जो किसी आलसी लोडिंग नहीं करना चाहिए। एक अन्य विकल्प खरीद संपत्ति को गैर-वर्चुअल बनाना है, हालांकि यह कहीं और आलसी लोडिंग को भी रोक देगा। – ChaseMedallion

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