2012-08-04 2 views
2

호출 스택이 없기 때문에 일부 LINQ를 SQL 코드로 디버깅하는 데 어려움을 겪고 있으며 오류가 발생한 위치를 알 수 없습니다. 그것은 SQL 오류가 아닌 것으로 보입니다. C#을 사용하지만 주위를 검색하면 오류를 제공하는 계산 방법을 찾을 수 없습니다.Visual Studio의 LINQ to SQL, 호출 스택이없는 InvalidCastException

소스 코드가 아래에 있으며 일부 새 행을 삽입하려고하면 오류가 표시됩니다. 호출 스택이 비어 있으며 예외에는 무엇이 잘못되었는지에 대한 정보가 없습니다.

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에 의해 생성 된 데이터베이스 쿼리가 오류 바로 전에 실행되었습니다. 나는 이중 변환을 전혀 보지 못했다.

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

을 달기보십시오 :

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 그것은 잘못보고하지 않습니다. 쿼리는 열거 될 때까지 연기됩니다. –

답변

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 다음에 선택하여 호출하여 만든 열거 자입니다. 새로운 요소로 이동하기 위해 실제로 수행해야 할 작업은 쿼리 결과 (ObjectReader.MoveNext)를 더 깊이 파고 들어가는 것인데 데이터베이스 결과에서 개체를 만들 것입니다. 이 시점에서


, 나는 당신이 startTimes의 유형을 말하지 않았다는 것을 지적하고 싶습니다. 내가 LinqToSql 쿼리 그래서, 데이터베이스 쿼리는 DataReader를 (스택에 캡처되지 않습니다)가되었습니다

startTimes을 추측하고있어, 우리가 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; 
} 

따라서 데이터 판독기 배열의 개체는 이중으로 변환되지 않습니다. 가장 가능성있는 가능성은 객체가 null이라는 것입니다!

다른 유형 (문자열 또는 바이트 [] 또는 무엇이든)이 원격으로있을 수도 있지만 LinqToSql의 디자이너를 사용하여 dbml 파일을 만들고 데이터베이스의 테이블이 해당 dbml과 일치하는 경우, 이것은있을 법하지 않습니다.


Convert.ToDouble은 호출 스택에 없습니다. 이 작업은 데이터베이스에서 수행되어야합니다. Convert.ToDouble은 실제로 호출되지 않습니다. -... 대신 SQL로 변환되어 실행됩니다. 유형 변환 규칙은 데이터베이스에서 다릅니다.

  • .net에서 null을 double로 변환하려고하면 예외가 발생합니다.
  • sql에서 null을 double로 변환하려고하면 null이됩니다.
+0

좋은 대답, 정확히 내가 생각한 것이지만 OP가 null 문제를 발견하게되기를 바랬습니다. – Hogan

+0

도움 주셔서 감사합니다. 문제가되는 줄은'avgDwell = g.Average (o => o.record.dwellTime) .GetValueOrDefault()', 즉 null 값에서 double을 얻으려고했던 마지막 부분입니다. 나는 이것이 어떻게 된 것인지 알려주지 않는 것을 싫어한다. 나는 무엇이 일어나고 있는지 알아낼 때까지 내 코드를 쳐다보아야한다. 실제 디버거가 우리를 그렇게해서는 안됩니다! –

+0

@AndrewMao 당신이 문제를 발견했기 때문에 기쁩니다. 디버거는 (아직) 데이터베이스 영역으로 선을 넘을 수 없으므로 디버거가 도달 할 수있는 첫 번째 지점에서 오류가 표시됩니다. –

1

좋아, 여기에 내가 무엇을보고, 예외의 두번째 라인은 한 번만 두 배로 변환 코드에

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

을 말한다있다 해당 줄에 g.Select(...)을 입력하고 예외가 계속 발생하는지 확인하십시오.

+0

그게 아니야. 해당 행을 주석 처리하고 상수 '0'으로 바꾸어도 문제가 해결되지 않습니다. –

+0

@AndrewMao 당신은 0.0으로 대체해야합니다 또는 당신은 동일한 오류가 발생합니다. – Hogan