2012-05-15 18 views
5

के साथ दक्षता में सुधार करना मैं पीओसीओ प्रथम दृष्टिकोण के साथ इकाई फ्रेमवर्क का उपयोग कर रहा हूं। SQL सर्वर से कनेक्ट करने के लिए डीआई कंटेनर और डीबीकॉन्टेक्स्ट क्लास का उपयोग करके स्टीव सैंडर्सन ने अपनी पुस्तक 'प्रो एएसपी.नेट एमवीसी 3 फ्रेमवर्क' में वर्णित पैटर्न का काफी पालन किया है।इकाई फ्रेमवर्क

SQL सर्वर में अंतर्निहित तालिकाओं में विभिन्न अनुप्रयोगों द्वारा उपयोग किए जाने वाले बहुत बड़े डेटासेट होते हैं। इस वजह से मैं संस्थाओं मैं अपने आवेदन में की जरूरत के लिए दृश्य बनाने के लिए पड़ा है:

class RemoteServerContext : DbContext 
{ 
    public DbSet<Customer> Customers { get; set; } 
    public DbSet<Order> Orders { get; set; } 
    public DbSet<Contact> Contacts { get; set; } 
    ... 

    protected override void OnModelCreating(DbModelBuilder modelBuilder) 
    { 
     modelBuilder.Entity<Customer>().ToTable("vw_Customers"); 
     modelBuilder.Entity<Order>().ToTable("vw_Orders"); 
     ... 
    } 
} 

और यह मेरा जरूरतों के अधिकांश के लिए ठीक से काम करने लगता है।

समस्या मेरे पास है

इन विचारों में से कुछ उन में डेटा का एक बड़ा सौदा है, ताकि जब मैं की तरह कुछ कहते हैं:

var customers = _repository.Customers().Where(c => c.Location == location).Where(...); 

यह पूरे डेटा सेट वापस लाने जा करने के लिए है, जो कर सकते हैं प्रकट होता है LINQ क्वेरी से सेट करने से पहले कुछ समय लें जो मुझे चाहिए। यह बहुत अक्षम लगता है जब मानदंड केवल कुछ रिकॉर्ड पर लागू होता है और मुझे पूरा डेटा SQL सर्वर से वापस सेट किया जा रहा है।

मैं संग्रहित प्रक्रियाओं का उपयोग करके इस को हल करने के लिए कोशिश की है, इस तरह के रूप

public IEnumerable<Customer> CustomersThatMatchACriteria(string criteria1, string criteria2, ...) //or an object passed in! 
{ 
    return Database.SqlQuery<Customer>("Exec pp_GetCustomersForCriteria @crit1 = {0}, @crit2 = {1}...", criteria1, criteria2,...); 
} 

इस दौरान बहुत जल्दी है, समस्या यहाँ है कि यह एक DbSet वापस नहीं करता है और इसलिए मैं खो मेरी वस्तुओं के बीच कनेक्टिविटी, उदाहरण के लिए मैं किसी भी संबंधित ऑब्जेक्ट्स जैसे ऑर्डर या संपर्कों का संदर्भ नहीं दे सकता, भले ही मैं अपनी आईडी शामिल करता हूं क्योंकि रिटर्न टाइप उनमें से एक डीबीसेट के बजाय 'ग्राहक' का संग्रह है।

क्या किसी के पास क्वेरीिंग करने के लिए SQL सर्वर प्राप्त करने का बेहतर तरीका है ताकि मैं अप्रयुक्त डेटा के भार को पास नहीं कर रहा हूं?

उत्तर

4
var customers = _repository.Customers().Where(c => c.Location == location).Where(... 

Customers() रिटर्न IQueryable, अकेले इस बयान नहीं वास्तव में किया कुछ भी 'वापस लाने' अगर - एक IQueryable पर Where बुला यदि आप किसी अन्य IQueryable देता है, और जब तक आप कुछ करना नहीं है कि क्वेरी निष्पादन का कारण बनता है (जैसे ToList, या FirstOrDefault) कि वास्तव में कुछ भी निष्पादित किया जाएगा और परिणाम लौटाए जाएंगे।

यदि यह Customers विधि तत्काल वस्तुओं का संग्रह लौटाता है, तो हाँ, क्योंकि आप उन सभी वस्तुओं के लिए पूछ रहे हैं जिन्हें आप उन्हें प्राप्त कर रहे हैं।

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

+0

+1। अधिक 'एक्स्टेंसिबल दृष्टिकोण' के लिए आप एक फ़ंक्शन लिख सकते हैं जो एक अनुमान लगाता है, और या तो '_repository.Customers() देता है। (कहां (predicate)' या (यदि यह अब IQueryable नहीं है) 'context.CreateQuery के साथ एक अलग फ़ंक्शन लिखें ("ग्राहक")। कहां (predicate) ', अंत में' .TLList() 'कॉल करने की संभावना के साथ। यह एक अच्छी, अनुकूलित अभिव्यक्ति का निर्माण करना चाहिए। –

+1

हाय। IQueryable के दायरे में रहने के लिए आप अपने सुझाव के साथ स्पॉट पर थे। मैं एक आईनेमरेबल का उपयोग कर रहा था जो सर्वर को क्वेरी पास नहीं करता है लेकिन सभी रिकॉर्ड्स प्राप्त करता है और फिर उन्हें फ़िल्टर करता है। यहां आलेख देखें: http://www.fascinatedwithsoftware.com/blog/post/2011/06/27/INumerable-IQueryable-and-the-Entity-Framework-40.aspx मैंने SQL प्रोफाइलर के साथ जांच की है और वह सही है, IQueryable पैरामीटर को एक क्वेरी के रूप में पास करता है – GrahamJRoy

0

एसक्यूएल में top फ़ंक्शन जैसे एसक्यूएल पेजिंग जैसे कम डेटा लौटने के लिए आपको LINQ क्वेरी की आवश्यकता है या संग्रहीत प्रक्रियाओं का उपयोग करके मैन्युअल क्वेरीिंग करें। किसी भी मामले में, आपको अपनी क्वेरीिंग तंत्र को फिर से लिखना होगा। यह एक कारण है कि मैंने ईएफ का उपयोग क्यों नहीं किया, क्योंकि आपके पास लगता है कि कोड पर बहुत अधिक नियंत्रण नहीं है।

2

मैं सिर्फ डेटा का एक सेट वापस जाने के लिए है | निम्नलिखित दिया क्या किया होता:

var customers = (from x in Repository.Customers where <boolean statement> &&/|| <boolean statement select new {variableName = x.Name , ...).Take(<integer amount for amount of records you need>); 
तो उदाहरण के लिए

:

var customers = (from x in _repository.Customers where x.ID == id select new {variableName = x.Name}).take(1000); 

तो डेटा प्राप्त करने के परिणामों के माध्यम से दोहराएं: (याद रखें, linq कथन एक IQueryable देता है) ...

foreach (var data in customers) 
{ 
    string doSomething = data.variableName; //to get data from your query. 
} 

उम्मीद है कि यह वास्तव में मदद करता है, बिल्कुल नहीं एक ही तरीके, लेकिन मुझे यह कोड

1

संभवतः ऐसा इसलिए है क्योंकि आपके भंडार में आपकी Cusomters() विधि GetAll() प्रकार की चीज़ कर रही है और पूरी सूची को पहले ला रही है। यह LINQ और आपके SQL सर्वर को स्मार्ट क्वेरीज़ बनाने से रोकता है।

मैं अपने भंडार के लिए एक अच्छा समाधान का हो, तो पता नहीं है, लेकिन अगर आप की तरह कुछ करना होगा:

using(var db = new RemoteServerContext()) 
{ 
    var custs = db.Customers.Where(...); 
} 

मुझे लगता है कि एक बहुत जल्दी हो जाएगा। यदि आपकी परियोजना काफी छोटी है, तो आप बिना किसी भंडार के कर सकते हैं। निश्चित रूप से, आप एक अमूर्त परत खो देंगे, लेकिन छोटी परियोजनाओं के साथ यह एक बड़ी समस्या नहीं हो सकती है।

दूसरी ओर, आप एक बार अपने ग्राहकों को अपने भंडार में लोड कर सकते हैं और परिणामस्वरूप संग्रह सीधे उपयोग कर सकते हैं (विधि-कॉल सूची को भरने के बजाय)। हालांकि ग्राहकों को जोड़ने, हटाने और संशोधित करने से सावधान रहें।

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