2011-02-24 22 views
10

मैं वास्तव में इस पर अटक गया हूं। मेरे पास एसक्यूएल में एक व्यापक पृष्ठभूमि है, लेकिन मैंने अभी एक नई नौकरी शुरू की है और वे सरल प्रश्नों के लिए LINQ का उपयोग करना पसंद करते हैं। तो सीखने की भावना में, मैं इस सरल SQL क्वेरी को फिर से लिखने का प्रयास किया:LINQ से SQL रूपांतरण ओवरफ़्लोज़

SELECT 
    AVG([Weight]/[Count]) AS [Average], 
    COUNT(*) AS [Count] 
FROM [dbo].[Average Weight] 
WHERE 
    [ID] = 187 

स्पष्टता रखने के लिए, यहाँ तालिका स्कीमा है:

CREATE TABLE [dbo].[Average Weight] 
(
    [ID] INT NOT NULL, 
    [Weight] DECIMAL(8, 4) NOT NULL, 
    [Count] INT NOT NULL, 
    [Date] DATETIME NOT NULL, 
    PRIMARY KEY([ID], [Date]) 
) 

यहाँ मैं के साथ आया है :

var averageWeight = Data.Context.AverageWeight 
    .Where(i => i.ID == 187) 
    .GroupBy(w => w.ID) 
    .Select(i => new { Average = i.Average(a => a.Weight/a.Count), Count = i.Count() }); 

डेटा.कॉन्टेक्स्ट.एवरवेयरइट SQLMetal द्वारा उत्पन्न SQL ऑब्जेक्ट का एक लिंक है। अगर मैं averageWeight.First() पर आज़माता हूं तो मुझे ओवरफ्लो एक्सेप्शन मिलता है। मैंने SQL प्रोफाइलर का उपयोग यह देखने के लिए किया कि LINQ द्वारा उत्पन्न parametrized क्वेरी कैसा दिखता है। फिर से इंडेंट कि इस तरह दिखता है:

EXEC sp_executesql N' 
SELECT TOP(1) 
    [t2].[value] AS [Average], 
    [t2].[value2] AS [Count] 
FROM (
     SELECT 
      AVG([t1].[value]) AS [value], 
      COUNT(*) AS [value2] 
     FROM (
       SELECT 
        [t0].[Weight]/(CONVERT(DECIMAL(29, 4), [t0].[Count])) AS 
        [value], 
        [t0].[ID] 
       FROM [dbo].[Average Weight] AS [t0] 
      ) AS [t1] 
     WHERE 
      ([t1].[ID] = @p0) 
     GROUP BY 
      [t1].[ID] 
    ) AS [t2]', 
    N'@p0 int', 
    @p0 = 187 

अत्यधिक नेस्टिंग अलग रूप में, मैं केवल एक समस्या देखें: दशमलव (29, 4)। (क्वेरी चलता है और अपेक्षित परिणाम देता है।) यह मेरी समझ है कि 28 से ऊपर कुछ भी सी # दशमलव डेटा प्रकार से बह जाएगा। [गणना] एक आईएनटी है इसलिए इसे कन्वर्ट करने की आवश्यकता है, लेकिन [वजन] एक निर्णायक (8, 4) है। मुझे कोई जानकारी नहीं है कि LINQ इतने बड़े डेटा प्रकार का उपयोग क्यों करेगा।

LINQ CONVERT डेटा प्रकार के कारण क्यों होता है जो कारण और बहती है? क्या इस व्यवहार को बदलने के लिए वैसे भी है? या मैं भी सही रास्ते पर हूँ?

इसके अलावा, Data.Context.AverageWeight एसक्लमैटल द्वारा उत्पन्न किया गया था और मैंने सत्यापित किया कि वजन एक दशमलव है और कॉलम विशेषता सही है (दशमलव (8,4))।

अग्रिम धन्यवाद।

अद्यतन: तो ऐसा लगता है कि LINQ से SQL SQL अपराधी हो सकता है।

SELECT TOP(1) 
    [t2].[value] AS [Average], 
    [t2].[value2] AS [Count] 
FROM (
     SELECT 
      AVG([t1].[value]) AS [value], 
      COUNT(*) AS [value2] 
     FROM (
       SELECT 
        [t0].[Weight]/(CONVERT(DECIMAL(16, 4), [t0].[Count])) AS [value], 
        [t0].[ID] 
       FROM [dbo].[Average Weight] AS [t0] 
      ) AS [t1] 
     WHERE 
      ([t1].[ID] = 187) 
     GROUP BY 
      [t1].[ID] 
    ) AS [t2] 

इस का परिणाम है::

Average     Count 
0.000518750000000  16 

पिछले दृष्टिकोण दिया:

var averageWeight = Data.Context.AverageWeight 
    .Where(i => i.ID == 187) 
    .GroupBy(w => w.ID) 
    .Select(i => new { Average = i.Average(a => a.Weight)/(decimal)i.Average(a => a.Count), Count = i.Count() }); 

अब एसक्यूएल इस तरह दिखता है उत्पन्न: मैं इस तरह मेरे LINQ बदल

Average     Count 
0.000518750000000000000 16 

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

कोई विचार?

+0

'कन्वर्ट (डेसिमल (...))' को * गणना * पर लागू किया जा रहा है, न कि 'वजन'। –

+0

क्या यह लिंक एसक्यूएल या एंटिटी फ्रेमवर्क है? –

+0

आप LINQ में समूह क्यों हैं लेकिन मूल एसक्यूएल नहीं? –

उत्तर

2

मैं कोई विशेषज्ञ हूँ, लेकिन एसक्यूएल-CLR प्रकार मानचित्रण टेबल को देखकर (http://msdn.microsoft.com/en-us/library/bb386947.aspx जैसे) आप देख सकते हैं एसक्यूएल दशमलव मानों को सीएलआर System.Decimal प्रकार में परिवर्तित कर दिया गया है और सीएलआर System.Decimal मान SQL DECIMAL(29,4) प्रकार में परिवर्तित हो गए हैं।

अपने उदाहरण में

तो, a.Weight किसी SQL दशमलव के रूप में एक CLR System.Decimal.a.Count द्वारा a.Weight के विभाजन इसलिए एक System.Decimal विभाजन और सही संकार्य (a.Count) के रूप में व्यवहार किया जाता है में बदल जाती है एक CLR करने के लिए परिवर्तित किया जाना चाहिए System.Decimal. Linq तो तब्दील इस प्रकार के रूपांतरण वापस एसक्यूएल जो गणना में जो परिणाम एक DECIMAL(29,4).

दुर्भाग्य में बदला जा रहा है,

a.Weight/(double) a.Count 

क्योंकि सही संकार्य काम नहीं करेगा System.Decimal में परिवर्तित किया जाना चाहिए, लेकिन एक डबल को स्वचालित रूप से एक int कैन की तरह रूपांतरित नहीं किया जा सकता है। हालांकि,

(double) a.Weight/a.Count 

काम करेंगे क्योंकि विभाजन अब, युगल का एक प्रभाग के रूप में इलाज नहीं है System.Decimals, तो जिसके परिणामस्वरूप एसक्यूएल इस तरह दिखता है:

SELECT (CONVERT(Float,[t0].[Weight]))/(CONVERT(Float,[t0].[Count])) AS [value] 
... 

Linq a.Count के इलाज के लिए क्या तुम सच में चाहते हैं हालांकि यह पहले से ही एक दशमलव है, एक int नहीं। आप अपनी डीबीएमएल फ़ाइल (see here) में गणना प्रकार का प्रकार बदलकर ऐसा कर सकते हैं। एसक्यूएल में

var averageweight = context.AverageWeights 
      .Where(i => i.ID == 187) 
      .GroupBy(w => w.ID) 
      .Select(i => new {Average = i.Average(a => a.Weight/a.Count), Count = i.Count()}); 

परिणाम::

SELECT AVG([t0].[Weight]/[t0].[Count]) AS [Average], COUNT(*) AS [Count] 
FROM [dbo].[AverageWeight] AS [t0] 
WHERE [t0].[ID] = @p0 
GROUP BY [t0].[ID] 

जो वांछित परिणाम है जब मैं इस, LINQ क्वेरी किया था। हालांकि, डीबीएमएल फ़ाइल में गणना गुण के प्रकार को बदलने से अन्य अनपेक्षित दुष्प्रभाव हो सकते हैं।

वैसे, आपके अद्यतन लिंक क्वेरी से जेनरेट किया गया SQL गलत लगता है। लिंक स्पष्ट रूप से आवश्यक है कि सभी वजनों का औसत सभी गणनाओं के औसत से विभाजित किया जाए, लेकिन एसक्यूएल ऐसा नहीं करता है। जब मैं एक ही LINQ क्वेरी लिखते हैं, एसक्यूएल मैं मिलता है: AVG के बजाय सिर्फ एक दो कॉल देखते हैं

SELECT [t1].[value]/(CONVERT(Decimal(29,4),[t1].[value2])) AS [Average], [t1].[value3] AS [Count] 
FROM (
    SELECT AVG([t0].[Weight]) AS [value], AVG([t0].[Count]) AS [value2], COUNT(*) AS [value3] 
    FROM [dbo].[Average Weight] AS [t0] 
    WHERE [t0].[ID] = @p0 
    GROUP BY [t0].[ID] 
    ) AS [t1] 

ध्यान दें कि। यह भी ध्यान रखें कि Decimal(29,4) में रूपांतरण अभी भी मौजूद है क्योंकि लिंक अभी भी System.Decimal डिवीजन कर रहा है।

0

मैं परीक्षण नहीं किया है, लेकिन आप a.Count कास्ट करने के लिए कोशिश कर सकते:

... a.Weight/(double) a.Count ... 
+0

यह शायद काम करेगा, लेकिन मुझे काम करने के लिए वजन को भी दोगुना करना होगा और फिर मेरा रिटर्न टाइप डबल होगा। मैं वास्तव में इसे सब कुछ फ़्लोटिंग पॉइंट डेटा प्रकारों में डालने का समाधान नहीं मानता। लिंक सही बिंदु संख्याओं का सही ढंग से उपयोग करने में सक्षम होना चाहिए। वैसे भी, मैं इस समस्या को ठीक करने के कई तरीकों के बारे में सोच सकता हूं। मैं वास्तव में उम्मीद कर रहा हूं कि कोई मुझे समझाने के लिए लिंक को समझता है कि यह क्यों हो रहा है ... – Ben

+0

इसके अलावा, (और दुर्भाग्य से) इसे दशमलव पर कास्टिंग (सी #) LINQ को SQL उत्पन्न करता है जिस तरह से नहीं बदलता है। – Ben