2014-10-29 9 views
6

मैं ग्राहकों और उनके वैकल्पिक मुख्य पते (ग्राहक के पास शून्य या अधिक पते हो सकते हैं) प्राप्त करने के लिए एक लिंक क्वेरी का उपयोग कर रहा हूं। वस्तु पदानुक्रम इस प्रकार है:लिंक क्वेरी NullReferenceException एकाधिक (कैस्केड) पर छोड़ दिया

  • ग्राहक
    • CustomerAddress
      • पता

इस क्वेरी मैं है (बूलियन संपत्ति मुख्य शामिल हैं) मैं उपयोग कर रहा हूँ :

var qry = from customer cus in GetDBContext(c).customer 
    join cusadd in GetDBContext(c).customeraddress on new { cus_code = cus.cus_code, main = "1" } equals new { cus_code = cusadd.cus_code, main = cusadd.Main_addr } into grpcusadd 
    from cusadd in grpcusadd.DefaultIfEmpty() 
    join add in GetDBContext(c).address on new { addr_code = cusadd.Addr_Code } equals new { addr_code = add.Addr_Code } into grpadd 
    from add in grpadd.DefaultIfEmpty() 
    select new { cus, cusadd, add }; 

var customers = qry.ToList(); 

जब मैं इसे डेटाबेस (ईएफ के माध्यम से) निष्पादित करता हूं तो यह मान सही ढंग से देता है। जब मैं इसे मेमोरी ऑब्जेक्ट्स के साथ एक मॉकिंग संदर्भ पर निष्पादित करता हूं, तो मुझे NullReferenceException मिलता है: ऑब्जेक्ट संदर्भ किसी ऑब्जेक्ट के उदाहरण पर सेट नहीं होता है।

मैं में शामिल होने क्योंकि पहली बाईं रिटर्न में शामिल होने के शून्य मान दूसरा बाएं भाग में स्थित एक अशक्त मान को चेक करके इस त्रुटि को ठीक करने में सक्षम था:

join add in GetDBContext(c).address on new { addr_code = cusadd == null ? null : cusadd.Addr_Code } equals new { addr_code = add.Addr_Code } into grpadd 

मैं एक ही निष्कर्ष के साथ एक ऐसे ब्लॉग पोस्ट पाया है लेकिन कोई स्पष्टीकरण नहीं: http://technologycraftsmen.net/blog/2010/04/14/multiple-outer-joins-in-linq-to-sql/

यह क्वेरी स्थानीय ऑब्जेक्ट्स पर क्यों विफल होती है, न कि डेटाबेस पर?

बाएं बाहरी बाएं कोनेड को हमेशा लिंक में इस तरह लिखा जाना चाहिए?

आपकी प्रतिक्रिया के लिए धन्यवाद!

उत्तर

6

लिंक अद्भुत है, लेकिन कोई अमूर्तता सही नहीं है। यह एक ऐसा मामला है जहां अंतर्निहित abstractions थोड़ा बाहर लीक कर रहे हैं।

जब अभिव्यक्ति वास्तविक संदर्भ के साथ निष्पादित की जाती है, तो इसे बाएं जॉइन का उपयोग करके एक ट्रांजैक्ट एसक्यूएल कथन में परिवर्तित कर दिया जाता है। अभिव्यक्ति को वास्तव में सीएलआर में निष्पादित नहीं किया जाता है, डेटाबेस में सबकुछ होता है। भले ही सही तालिका में कोई मेल खाने वाले रिकॉर्ड न हों, क्वेरी सफल हो जाती है।

अपने मॉक किए गए संदर्भ के विरुद्ध क्वेरी निष्पादित करते समय, सीएलआर में वास्तविक क्वेरी निष्पादन हो रहा है और डेटाबेस में नहीं। उस बिंदु पर, अभिव्यक्ति इस तरह काम करती है जैसे आपने गैर-LINQ C# कोड लिखा था। इसका मतलब है कि किसी ऑब्जेक्ट की संपत्ति के खिलाफ एक परीक्षण जो शून्य है, वह NullReferenceException को फेंक देगा जो आप देख रहे हैं।

यह कल्पना करना क्या हुआ अगर यह सिर्फ एक तरह दो दृश्यों के बीच में शामिल होने गया था क्या होगा उपयोगी हो सकता है:

var customers = new List<Customer> { new Customer { Id = 1, Name = "HasAddress" }, new Customer { Id = 2, Name = "HasNoAddress" } }; 

var addresses = new List<Address> { new Address { Id = 1, CustomerId = 1, Street = "123 Conselyea Street" } }; 


var customerAddresses = from Customer cus in customers 
         join address in addresses on cus.Id equals address.CustomerId into grouped 
         from ca in grouped.DefaultIfEmpty() 
         select new { CustomerId = cus.Id, Name = cus.Name, Street = ca.Street }; 

काम "स्ट्रीट = ca.Street" हमारी दूसरी ग्राहक है, क्योंकि, एक NullReferenceException फेंक होगा कोई मिलान पता नहीं हम इसे कैसे ठीक करेंगे?एक त्रिगुट ऑपरेटर आप जैसे व्यापक करने के लिए अपने को ठीक करने में शामिल के साथ शामिल हो:

var customerAddresses = from Customer cus in customers 
         join address in addresses on cus.Id equals address.CustomerId into grouped 
         from ca in grouped.DefaultIfEmpty() 
         select new { CustomerId = cus.Id, Name = cus.Name, Street = (ca != null) ? ca.Street : null }; 

मामले में जहां संदर्भ मजाक कर रहे हैं, अपने व्यापक में शामिल होने के एक चलाना एसक्यूएल में शामिल नहीं है, यह सिर्फ एक सामान्य सी # उपयोग है मेरे उदाहरण में वस्तुओं और अनुक्रमों के रूप में।

मुझे सीएलआर में निष्पादन और डेटाबेस में निष्पादन के बीच नियमों में मतभेदों से अनजान होने के लिए अपना कोड लिखने के किसी भी तरीके से नहीं पता है। DefaultIfEmpty विधि कॉल में डिफ़ॉल्ट उदाहरण प्रदान करके कुछ मुश्किल करना संभव हो सकता है, लेकिन यह मेरे लिए हैकी लगता है।

उम्मीद है कि हमारे पास सी # में शून्य प्रचारक ऑपरेटर होने के बाद यह बेहतर हो जाएगा।

+1

आपके उत्तर के लिए धन्यवाद! निष्कर्ष: यदि लिंक क्वेरी डेटाबेस और सीएलआर दोनों में निष्पादित की जाएगी, तो क्वेरी दोनों मामलों के साथ मुद्दों को संभालना चाहिए। शून्य प्रचारक ऑपरेटर वास्तव में क्लीनर कोड प्रदान कर सकता है। –

+2

ग्रेट उत्तर, मैंने मेमोरी प्रस्तुति में दिए गए परीक्षण के साथ इसे स्वयं में चलाया है। कठिनाई यह सुनिश्चित कर रही है कि आप किसी विधि या ऑपरेटर का उपयोग न करें जो डेटाबेस के लिए अनुवाद योग्य नहीं है, अन्यथा यह डेटाबेस से अधिक फेंकने या वापस करने को समाप्त कर देगा, फिर उम्मीद है कि फिर फ़िल्टर फ़िल्टर पर सीएलआर कोड चलाएगा। –

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