2012-08-04 73 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