2011-08-22 14 views
13

Mi procedimiento almacenado:excepción de difusión no válida cuando se lee resultado de SQLDataReader

@UserName nvarchar(64), 

    AS 

    BEGIN 
    SELECT MPU.UserName, SUM(TS.Monday)as Monday //TS.Monday contains float value 
    FROM dbo.MapTask MT JOIN dbo.MapPU MPU 
    ON MPU.ID = MT.MPUID 
    JOIN dbo.TimeSheet TS 
    ON MT.TMSID = TS.ID 
    WHERE MT.StartDate = @StartDate_int and MPU.UserName = @UserName 
    GROUP BY MPU.UserName 
    END 

En mi código C#

SqlDataReader reader = command.ExecuteReader(); 

     while (reader.Read()) 
     { 
      float monday = (float)reader["Monday"]; // Invalid cast exception 
     } 

Puede alguien decirme lo que hice mal? Gracias.

+0

Puede intentar Convert.ToFloat (reader ["Monday"]. ToString()); – Jethro

+0

@Jethro: Es una forma bastante horrible de hacerlo. Cuando una conversión falla, reemplazarla con * dos * conversiones (hacia y desde la cadena) generalmente * no * es una buena idea. –

+0

@Jon Skeet, eso tiene sentido, además de que Convert.ToFloat no existe. Necesito ser más cuidadoso Si Convert.ToFloat existiera, sería mejor hacer esto luego. Convert.ToFloat (lector ["lunes"]); ?? – Jethro

Respuesta

30

Supongo que el valor se devuelve como un double en caja en lugar de float. Cuando desempaquete el tipo tiene que ser exactamente derecha. Así que asumiendo que estoy bien y no es decimal o algo por el estilo, que puede usar:

float monday = (float) (double) reader["Monday"]; 

y que iba a funcionar. Aunque eso es bastante feo. Si usa SqlDataReader.GetFloat, debe hacerlo bien si es genuinamente un valor de precisión simple, y está más claro (IMO) lo que está sucediendo.

Por otro lado, los datos podrían realidad estar regresando de la base de datos como un double, en cuyo caso se debe (OMI) utiliza:

float monday = (float) reader.GetDouble(column); 

Como acotación al margen, ¿está seguro de que float es en realidad el tipo más apropiado aquí en primer lugar? A menudo decimal es más apropiado ...

+14

Si el tipo de datos en SQL Server es "flotante", la llamada a SqlDataReader.GetFloat desafortunadamente generará un error, porque las convenciones de nomenclatura son completamente incompatibles. Un "flotante" SQL es en realidad un valor de precisión doble y, por lo tanto, se asigna a un doble .NET. Un SQL "real" es la precisión simple que se asigna a un flotador .NET. Los nombres de .NET son internamente inconsistentes, en lugar de elegir "doble" e "único" como palabras clave, mezcla "flotante", mientras que en SQL es "flotante" y "real" sin referencia a la precisión doble o única. – Triynko

11

Un sql float es .NET Double, consulte en el msdn. Prueba a lanzar al doble.

+0

Puedes intentar lanzar al doble y luego flotar, eso es lo que hago. – TheGateKeeper

+0

Esta es la respuesta correcta. La excepción de conversión ocurre porque el servidor SQL usa "flotante" y "real" para referirse a los valores de precisión doble y simple respectivamente. Me imagino que es un error común intentar llamar a SqlDataReader.GetFloat en un campo SQL "flotante", porque eso tendría sentido, pero desafortunadamente, debe llamar a SqlDataReader.GetDouble. Y si tenía la intención de almacenar un valor de precisión única, volver a la base de datos para cambiar el tipo de "flotante" a "real". Deberían haberse limitado a "float32", "float64", "int32", int64 "en lugar de todo este" pequeño "" pequeño "" grande "" real "" simple "" sin sentido "doble. – Triynko

1

También tuve un problema similar y terminó haciendo esto:

if (!oDR.IsDBNull(0)) 
    Rating = (float)oDR.GetSqlDecimal(0).Value; 

oDR.GetFloat (0) estaba regresando y no válida excepción de difusión al acceder al resultado de un SELECT AVG (...) .

HTH

Cuestiones relacionadas