2012-08-04 100 views
2

我很難調試一些LINQ to SQL代碼,因爲沒有調用堆棧,我不知道錯誤發生的位置。它似乎不是一個SQL錯誤 - 它在C#中,但是通過搜索和其他一切,我找不到任何方法來找出哪個計算給出錯誤。LINQ to SQL in Visual Studio,InvalidCastException with no call stack

源代碼如下,當我嘗試插入一些新行時,可以看到引發的錯誤。調用堆棧是空的,並且異常不包含有關錯誤的信息。

var groups = 
    from record in startTimes 
    group record by record.startTime 
    into g 
    select new 
       {         
        startTime = g.Key.GetValueOrDefault(), 
        totalTasks = g.Count(), 
        totalTime = g.Max(o => o.record.timeInSession).GetValueOrDefault(), 
        minDwell = g.Min(o => o.record.dwellTime).GetValueOrDefault(), 
        maxDwell = g.Max(o => o.record.dwellTime).GetValueOrDefault(), 
        avgDwell = g.Average(o => o.record.dwellTime).GetValueOrDefault(), 
        stdevDwell = g.Select(o => Convert.ToDouble(o.record.dwellTime)).StdDev(), 
        correct80 = g.Sum(o => o.record.correct80.GetValueOrDefault() ? 1 : 0), 
        wrong80 = g.Sum(o => o.record.wrong80.GetValueOrDefault() ? 1 : 0) 
       }; 

var statistics = groups.AsEnumerable().Select(
    g => new e_activeSession() 
      { 
       workerId = wcopy, 
       startTime = g.startTime, 
       totalTasks = g.totalTasks, 
       totalTime = g.totalTime, 
       minDwell = g.minDwell, 
       maxDwell = g.maxDwell, 
       avgDwell = g.avgDwell, 
       stdevDwell = g.stdevDwell, 
       total80 = g.correct80 + g.wrong80, 
       correct80 = g.correct80, 
       percent80 = g.correct80/(g.correct80 + g.wrong80)         
      } 
    );          

// Put these rows into the table     
_gzClasses.e_activeSessions.InsertAllOnSubmit(statistics);     
_gzClasses.SubmitChanges(); 

Call stack and generally unhelpful exception

下面是異常的堆棧跟蹤。如果任何人都可以破譯它,請告訴我,因爲我不知道如何閱讀這些匿名類型...

at System.Data.SqlClient.SqlBuffer.get_Double() 
at System.Data.SqlClient.SqlDataReader.GetDouble(Int32 i) 
at Read_<>f__AnonymousType2`9(ObjectMaterializer`1) 
at System.Data.Linq.SqlClient.ObjectReaderCompiler.ObjectReader`2.MoveNext() 
at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext() 
at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection) 
at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source) 
at System.Data.Linq.Table`1.InsertAllOnSubmit[TSubEntity](IEnumerable`1 entities) 

而且,我已經運行在LINQPad這個查詢,並得到了同樣的錯誤和堆棧跟蹤。最後,這是LINQ to SQL生成的數據庫查詢,在錯誤發生之前執行。我根本沒有看到任何雙重轉換。

SELECT COALESCE([t5].[value22],'1/1/0001 12:00:00 AM') AS [startTime], [t5].[value] AS [totalTasks], COALESCE([t5].[value2],0) AS [totalTime], COALESCE([t5].[value3],0) AS [minDwell], COALESCE([t5].[value4],0) AS [maxDwell], COALESCE([t5].[value5],0) AS [avgDwell], [t5].[value6] AS [correct80], [t5].[value7] AS [wrong80], [t5].[value22] 
FROM (
    SELECT COUNT(*) AS [value], MAX([t4].[timeInSession]) AS [value2], MIN([t4].[dwellTime]) AS [value3], MAX([t4].[dwellTime]) AS [value4], AVG([t4].[dwellTime]) AS [value5], SUM([t4].[value3]) AS [value6], SUM([t4].[value]) AS [value7], [t4].[value2] AS [value22] 
    FROM (
     SELECT 
      (CASE 
       WHEN (COALESCE([t3].[wrong80],0)) = 1 THEN @p4 
       ELSE @p5 
      END) AS [value], [t3].[workerID], [t3].[value2], [t3].[timeInSession], [t3].[dwellTime], [t3].[value] AS [value3] 
     FROM (
      SELECT 
       (CASE 
        WHEN (COALESCE([t2].[correct80],0)) = 1 THEN @p2 
        ELSE @p3 
       END) AS [value], [t2].[wrong80], [t2].[workerID], [t2].[value] AS [value2], [t2].[timeInSession], [t2].[dwellTime] 
      FROM (
       SELECT (
        SELECT MAX([t1].[timeStamp]) 
        FROM [dbo].[workerLog] AS [t1] 
        WHERE ([t1].[dwellTime] IS NULL) AND ([t1].[timeInSession] = @p0) AND ([t1].[workerID] = @p1) AND ([t1].[timeStamp] <= [t0].[timeStamp]) 
        ) AS [value], [t0].[workerID], [t0].[dwellTime], [t0].[timeInSession], [t0].[correct80], [t0].[wrong80] 
       FROM [dbo].[workerLog] AS [t0] 
       ) AS [t2] 
      ) AS [t3] 
     ) AS [t4] 
    WHERE [t4].[workerID] = @p6 
    GROUP BY [t4].[value2] 
    ) AS [t5] 
+1

@pst它沒有誤報,查詢被推遲到枚舉。 – 2012-08-04 05:13:42

回答

3

讓我們讀到調用堆棧:

at System.Data.SqlClient.SqlBuffer.get_Double() 
at System.Data.SqlClient.SqlDataReader.GetDouble(Int32 i) 
at Read_<>f__AnonymousType2`9(ObjectMaterializer`1) 
at System.Data.Linq.SqlClient.ObjectReaderCompiler.ObjectReader`2.MoveNext() 
at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext() 
at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection) 
at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source) 
at System.Data.Linq.Table`1.InsertAllOnSubmit[TSubEntity](IEnumerable`1 entities) 

InsertAllOnSubmit是堆棧的頂部。它調用了ToList,它調用了List的「ctor」,意思是構造函數。

該List構造函數枚舉其參數(延遲查詢),導致查詢被解析。

在列表構造函數的枚舉過程中,我們嘗試移動到查詢中的下一個元素(WhereSelectEnumerableIterator.MoveNext) - 這是您在AsEnumerable之後調用Select所創建的枚舉數。爲了移至新元素,我們實際需要做的是深入查詢(ObjectReader.MoveNext),該查詢將從數據庫結果創建一些對象。


在這一點上,我想指出的是,你不說的類型startTimes。我猜startTimes是LinqToSql查詢


所以,該數據庫查詢被變成一個DataReader(在棧上無法捕捉到),而且我們從DataReader的提取行(Read_<>f__AnonymousType2 9(ObjectMaterializer 1))所以我們可以將該行轉換爲作爲查詢結果的.net實例。

在從行中提取值的過程中,涉及到一個雙重值,所以我們嘗試提取(.GetDouble(Int32 i).get_Double()),。現在,我們知道DataReader可以將其值視爲object[](參考SqlDataReader.GetValues)。這似乎是合理的,GetDouble可能會實現這樣的事情:

//rubbish implementation, the point is - a cast from object to double is made 
public double GetDouble(Int32 i)  { 
    double result = (double) this.GetValues()[i]; 
    return result; 
} 

因此,數據讀取器數組中的對象不會轉換爲double。 最可能的可能性是該對象爲空!

也可能存在某種其他類型(字符串或字節[]或其他),但如果您使用LinqToSql的設計器創建dbml文件,並且數據庫中的表仍然與該dbml一致,這不太可能。


我看到Convert.ToDouble不在調用堆棧中。這必須在數據庫之前完成。 Convert.ToDouble是 - 實際上沒有被稱爲-...,而是被轉換爲sql並在那裏運行。數據庫中的類型轉換規則不同。

  • 如果您嘗試將null轉換爲.net中的double,則會發生異常。
  • 如果您嘗試將null轉換爲sql中的雙精度型,則會得到空值。
+0

很好的答案,正是我的想法,但希望OP會發現空問題。 – Hogan 2012-08-04 11:30:00

+0

感謝您的幫助。有問題的行是'avgDwell = g.Average(o => o.record.dwellTime).GetValueOrDefault()',即最後一部分,它試圖從空值中獲得一個double。我討厭它如何不告訴我這是什麼原因造成的,我必須盯着我的代碼,直到我弄清楚發生了什麼。真正的調試器不應該讓我們這樣做! – 2012-08-06 17:15:24

+0

@AndrewMao很高興你發現了這個問題。調試器無法(至今)不能跨越數據庫世界,所以在調試器可以到達的第一個點上看到錯誤。 – 2012-08-06 17:28:39

1

好吧,這裏是我所看到的,在異常二號線說

at System.Data.SqlClient.SqlDataReader.GetDouble(Int32 i)... 

在你的代碼只能轉換爲雙旦:

stdevDwell = g.Select(o => Convert.ToDouble(o.record.dwellTime)).StdDev(), 

嘗試註釋掉g.Select(...),看看你是否仍然有異常。

+0

不是這樣。註釋掉該行並用常量'0'替換並不能解決問題。 – 2012-08-06 16:57:38

+0

@AndrewMao你需要用0.0代替它,否則你會得到相同的錯誤。 – Hogan 2012-08-06 18:07:43