2011-08-22 15 views
13

mia stored procedure:eccezione fusione non valido durante la lettura risultato da 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 

Nel mio codice C#

SqlDataReader reader = command.ExecuteReader(); 

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

Qualcuno può dirmi che cosa ho fatto di sbagliato? Grazie.

+0

È possibile provare Convert.ToFloat (lettore ["Monday"]. ToString()); – Jethro

+0

@Jethro: Questo è un modo piuttosto orribile di farlo però. Quando una conversione fallisce, sostituendola con * due * conversioni (da e verso la stringa) generalmente * non * è una buona idea. –

+0

@Jon Skeet, ha senso, oltre a Convert.ToFloat non esiste. Devi essere più attento. Se Convert.ToFloat esistesse sarebbe meglio fare questo allora. Convert.ToFloat (lettore [ "Lunedi"]); ?? – Jethro

risposta

30

La mia ipotesi è che il valore viene restituito come una scatola double anziché float. Quando si annulla il tipo deve essere esattamente a destra. Quindi, supponendo che ho ragione e non è decimal o qualcosa del genere, è possibile utilizzare:

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

e che avrebbe funzionato. Questo è piuttosto brutto però. Se si utilizza SqlDataReader.GetFloat, dovrebbe farlo correttamente se è veramente un valore a precisione singola ed è più chiaro (IMO) cosa sta succedendo.

D'altra parte, i dati potrebbero realtà essere di ritorno dal database come un double, nel qual caso si dovrebbe (IMO) usa:

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

Per inciso, sei sicuro che float è in realtà il tipo più appropriato qui in primo luogo? Spesso lo decimal è più appropriato ...

+14

Se il tipo di dati in SQL Server è "float", chiamare SqlDataReader.GetFloat genera purtroppo un errore, poiché le convenzioni di denominazione sono completamente incompatibili. Un "float" SQL è in realtà un valore a precisione doppia e quindi esegue il mapping a un doppio .NET. Un "reale" SQL è la precisione singola che esegue il mapping su un float .NET. I nomi di .NET sono internamente incoerenti, invece di scegliere "double" e "single" come parole chiave, mescola "float" in, mentre in SQL è "float" e "reale" senza alcun riferimento alla precisione doppia o singola. – Triynko

11

Un sql float è un .NET Double, vedere su msdn. Prova a trasmettere a un doppio.

+0

Puoi provare a trasmettere per raddoppiare e poi a fluttuare, questo è quello che faccio. – TheGateKeeper

+0

Questa è la risposta corretta. L'eccezione del cast si verifica perché i server SQL utilizzano "float" e "real" per riferirsi rispettivamente ai valori double e single-precision. Immagino sia un errore comune provare a chiamare SqlDataReader.GetFloat su un campo "float" SQL, perché avrebbe senso, ma ahimè, devi chiamare SqlDataReader.GetDouble. E se intendevi memorizzare un valore a precisione singola, torna al database per cambiare il tipo da "float" a "real". Dovrebbero essere semplicemente rimasti in "float32", "float64", "int32", int64 "invece di tutta questa" piccola "" piccola "" grande "" vera "" singola "" doppia "assurdità. – Triynko

1

Ho anche avuto un problema simile e finito per fare questo:

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

oDR.GetFloat (0) stava tornando ed eccezione fusione non valida quando si accede il risultato di un SELEZIONA AVG (...) .

HTH

Problemi correlati