कैसे LINQ Sum () को 0 वापस करने के लिए मजबूर करें जबकि स्रोत संग्रह खाली है


183

मूल रूप से जब मैं निम्नलिखित क्वेरी करता हूं, अगर कोई लीड नहीं मिला तो निम्नलिखित क्वेरी एक अपवाद फेंकता है। उस स्थिति में, मैं एक अपवाद को फेंके जाने के बजाय 0 बराबर करना चाहता हूं। क्या यह क्वेरी में ही संभव होगा - मेरा मतलब है कि क्वेरी को संग्रहीत करने और जाँच करने के बजाय query.Any()?

double earnings = db.Leads.Where(l => l.Date.Day == date.Day
                && l.Date.Month == date.Month
                && l.Date.Year == date.Year
                && l.Property.Type == ProtectedPropertyType.Password
                && l.Property.PropertyId == PropertyId).Sum(l => l.Amount);

2
Whereवापस नहीं किया जाएगा null, तो यह किसी भी रिकॉर्ड नहीं मिला, यह शून्य मदों की एक सूची लौट आते हैं। अपवाद क्या है?
माइक पेरेनॉउड

3
अपवाद क्या है?
टोटो

3
मुझे इसका अपवाद मिलता है: 'वैल्यू' टाइप 'इंट 32' के लिए कास्ट विफल रही क्योंकि भौतिक मूल्य शून्य है। या तो परिणाम प्रकार के सामान्य पैरामीटर या क्वेरी को एक अशक्त प्रकार का उपयोग करना चाहिए।
जॉन मेयर

1
@Stijn, नहीं, जो आपने अभी भी नहीं किया है वह काम नहीं करेगा। मुद्दा जिस तरह SQLसे उत्पन्न होता है। Amountवास्तव में नहीं है null, यह वास्तव में एक समस्या है कि यह शून्य परिणामों को कैसे संभालती है। प्रदान किए गए उत्तर पर एक नज़र डालें।
माइक पेरेनॉउड

39
आपको डॉलर की मात्रा के लिए दोगुना उपयोग नहीं करना चाहिए ! भिन्नात्मक डॉलर की मात्रा भी। एक सटीक राशि का इरादा होने पर कभी भी, कभी भी, कभी भी डबल का उपयोग करें। आपका डेटाबेस कॉलम होना चाहिए decimal, आपका कोड उपयोग करना चाहिए decimal। आप कभी भी floatऔर doubleअपने प्रोग्रामिंग करियर के बारे में तब तक जान सकते हैं जब तक कि कोई आपको आंकड़ों या स्टार ल्यूमिनेंस या एक स्टोकेस्टिक प्रक्रिया या इलेक्ट्रॉन के चार्ज के परिणामों के लिए उनका उपयोग करने के लिए न कहे! तब तक, आप इसे गलत कर रहे हैं
एरिक

जवाबों:


390

इसमें अपनी क्वेरी बदलने का प्रयास करें:

db.Leads.Where(l => l.Date.Day == date.Day
            && l.Date.Month == date.Month
            && l.Date.Year == date.Year
            && l.Property.Type == ProtectedPropertyType.Password
            && l.Property.PropertyId == PropertyId)
         .Select(l => l.Amount)
         .DefaultIfEmpty(0)
         .Sum();

इस तरह, आपकी क्वेरी केवल Amountफ़ील्ड का चयन करेगी । यदि संग्रह खाली है, तो यह एक तत्व के मूल्य के साथ वापस आ जाएगा 0और फिर योग लागू होगा।


यह निश्चित रूप से ट्रिक करता है, लेकिन क्या यह Sumडेटाबेस मानों के बजाय, पहले और सर्वर साइड पर राशि मानों की सूची का चयन नहीं करेगा ? imo 2kay का समाधान अधिक इष्टतम है, कम से कम अधिक शब्दार्थिक रूप से सही है।
मक्सीम वी।

3
जब @MaksimVI एफई, पहले भौतिकीकरण पर क्वेरी उत्पन्न होगा IQueryable<T>श्रृंखला बंद हो जाता है (आम तौर पर जब आप कॉल ToList, AsEnumerable, आदि .. और इस मामले में Sum)। SumEF क्वेरी प्रदाता द्वारा एक ज्ञात और नियंत्रित तरीका है और संबंधित SQL स्टेटमेंट उत्पन्न करेगा।
साइमन बेलेंगर

@SimonBelanger मैं सही खड़ा हूं, योग DB की तरफ से बना है, लेकिन यह एक उपश्रेणी पर बनाया गया है जो पहले राशियों का चयन करता है। मूल रूप से क्वेरी SELECT SUM(a.Amount) FROM (SELECT Amount FROM Leads WHERE ...) AS aसिर्फ के बजाय है SELECT SUM(Amount) FROM Leads। इसके अलावा सबक्वेरी में एक अतिरिक्त अशक्त जांच और एक एकल पंक्ति तालिका के साथ एक अजीब बाहरी जुड़ाव है।
मक्सीम वी।

महत्वपूर्ण प्रदर्शन अंतर नहीं है और यह शायद अनुकूलित है, लेकिन मुझे अभी भी लगता है कि अन्य समाधान क्लीनर दिखता है।
मक्सीम वी।

5
ज्ञात हो कि DefaultIfEmptyकई लाइनक्यू प्रदाताओं द्वारा समर्थित नहीं है, इसलिए आपको ToList()उन मामलों में इसका उपयोग करने से पहले या कुछ इसी तरह फेंकना होगा ताकि यह LINQ ऑब्जेक्ट परिदृश्य में लागू हो ।
क्रिस्टोफर किंग

188

मैं एक और हैक का उपयोग करना पसंद करता हूं:

double earnings = db.Leads.Where(l => l.Date.Day == date.Day
                                      && l.Date.Month == date.Month
                                      && l.Date.Year == date.Year
                                      && l.Property.Type == ProtectedPropertyType.Password
                                      && l.Property.PropertyId == PropertyId)
                          .Sum(l => (double?) l.Amount) ?? 0;

18
जब SQL को Linq का उपयोग करते हैं तो यह स्वीकृत उत्तर की तुलना में बहुत छोटा SQL कोड उत्पन्न करता है
wertzui

3
यह सही जवाब है। अन्य सभी असफल। पहले अशक्त करने के लिए कास्टिंग और फिर अशक्त के खिलाफ अंतिम परिणाम की तुलना।
मोहसिन अफशीन

3
यह Linq To EF के लिए स्वीकृत उत्तर से बहुत बेहतर है। मेरे लिए उत्पन्न SQL DefaultIfEmpty से लगभग 3.8 गुना बेहतर प्रदर्शन करता है।
फ्लोरियन

2
यह बहुत तेजी से है।
फ्राकॉन

1
मैं इसे हैक नहीं कहूंगा, क्योंकि यह सटीक उपयोग नलिका के लिए डिज़ाइन किया गया है, अर्थात बिना डेटा और डिफ़ॉल्ट मान के बीच अंतर दिखाते हुए
माइक जूल


4

मेरे लिए यह जीत है:

int Total = 0;
Total = (int)Db.Logins.Where(L => L.id == item.MyId).Sum(L => (int?)L.NumberOfLogins ?? 0);

मेरे लोगो की तालिका में, फ़ील्ड में कुछ मान NULL हैं और अन्य में INT नंबर है। मैं यहां एक निगम (प्रत्येक आईडी) के सभी उपयोगकर्ताओं के कुल संख्याओं का योग करता हूं।


1

प्रयत्न:

दोहरी कमाई = db.Leads.Where (l => l.houldBeIncluded) .सुम (l => (डबल?) l.Amount) ?? 0 ;

खाली सूची के लिए " SELECT SUM ([राशि]) " क्वेरी NULL वापस आ जाएगी। लेकिन यदि आप LINQ का उपयोग करते हैं तो यह उम्मीद करता है कि " Sum (l => l.Amount) " दोहरा रिटर्न देता है और यह आपको खाली संग्रह के लिए 0 सेट करने के लिए " ?? " ऑपरेटर का उपयोग करने की अनुमति नहीं देता है ।

इस स्थिति से बचने के लिए आपको LINQ " डबल " की अपेक्षा करने की आवश्यकता है । आप इसे कास्टिंग करके कर सकते हैं " (दोहरा?) L.Amount "।

यह SQL को क्वेरी को प्रभावित नहीं करता है लेकिन यह LINQ को खाली संग्रह के लिए काम करता है।


0
db.Leads.Where(l => l.Date.Day == date.Day
        && l.Date.Month == date.Month
        && l.Date.Year == date.Year
        && l.Property.Type == ProtectedPropertyType.Password
        && l.Property.PropertyId == PropertyId)
     .Select(l => l.Amount)
     .ToList()
     .Sum();

1
कृपया कोड के बारे में जवाब के लिए कुछ जानकारी जोड़ें
Jaenen H'ghar

1
जब मुझे टोललिस्ट () के बिना प्रयास करने में त्रुटि हुई, क्योंकि यह कुछ भी नहीं लौटाता है। लेकिन ToList () खाली सूची बना देगा और जब मैं ToList ()। Sum () करता हूं तो यह कोई त्रुटि नहीं देता है।
मोना

2
आप शायद ToListयहाँ उपयोग नहीं करना चाहते हैं यदि आप चाहते हैं कि सभी राशि है। यह पूरे परिणाम सेट को ( Amountइस मामले में प्रत्येक रिकॉर्ड के लिए) मेमोरी में और फिर Sum()उस सेट पर लौटा देगा । एक और समाधान का उपयोग करने के लिए बेहतर है जो एसक्यूएल सर्वर के माध्यम से गणना करता है।
जोश एम।
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.