12

When my website gets to the following bit of code, it falls down with an exception as follows:

System.InvalidCastException: Object cannot be cast from DBNull to other types.

For the interests of brevity, I'm showing only the relevant code (it's a 4000+ LOC file I've been given).

if (dr["STAGE"] is DBNull)
{
    dto.Stage = 1; // This is the line throwing the exception, according to stack trace
}
else
{
    dto.Stage = Convert.ToInt32(dr["STAGE"]);
}

Here, dr is a DataRow object that is the result of a query to a database, dto is a basic class that just holds some properties, of which dto.Stage is an int member.

I've looked at other questions with the same error message, but most of them seem to suggest "Check if it's DBNull", which I'm already doing.

So can someone suggest a solution?

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
TZHX
  • 5,291
  • 15
  • 47
  • 56
  • 1
    I am not sure but it seems the error is caused by dto.Stage = Convert.ToInt32(dr["STAGE"]); try using DBNULL.value – Kamran Pervaiz Jun 26 '12 at 14:15
  • @Kamran - but it's not reaching that point, the exception is thrown on the line containing `dto.Stage = 1`. – TZHX Jun 26 '12 at 14:18
  • 3
    Ignore the **exact** line number in the stack-trace; the numbers can be slightly off - I see that all the time. Run it in a debugger with break-points instead, or just add extra logging while you nail it down. – Marc Gravell Jun 26 '12 at 14:18
  • 1
    hehe, there's a reason I use dapper... to avoid all this fun! – Marc Gravell Jun 26 '12 at 14:20
  • if the error is being thrown when you are trying to set dto.Stage = 1, then its possible that dto is null? – tardomatic Jun 26 '12 at 14:23
  • @tardomatic no, dto is not a database object, and is created using new half a dozen lines above the snippet I've included. – TZHX Jun 26 '12 at 14:26
  • I think @MarcGravell has a point, if I add a `throw` in before the `dto.Stage=1;` then the `DBNull` exception occurs elsewhere. :| Damn stack trace leading me down the wrong path. – TZHX Jun 26 '12 at 14:28
  • Are you able to reproduce this in the IDE debugger, or does it only happen in the wild? If you can't do it in the debugger, make absolutely sure your PDB files are up-to-date with the assemblies. If the PDB's don't match (were from a different build), then the line numbers if gives may not be accurate. – Steven Doggart Jun 26 '12 at 14:30
  • @TZHX : Please validate an answer. – Aelios Oct 09 '12 at 09:52
  • @TZHX : sorry, my bad ;) I did not see your selected answer. – Aelios Oct 09 '12 at 11:35

5 Answers5

5

Use == instead of is

if (dr["STAGE"] == DBNull.Value)
{

}
Aelios
  • 11,849
  • 2
  • 36
  • 54
2

Use this slightly more efficient approach

int stageOrdinal = dr.GetOrdinal("STAGE");
while (dr.Read()) {
     dto = new DataTransferObject();
     if (dr.IsDBNull(stageOrdinal)) {
         dto.Stage = 1;
     } else {
         dto.Stage = dr.GetInt32(stageOrdinal);
     }
     //TODO: retrieve other columns.
     dtoList.Add(dto);
}

Accessing the columns by their index is faster than accessing them by name. The index of a column can be retrieved with the GetOrdinal method of the DataReader. This is best done before the loop.

Olivier Jacot-Descombes
  • 104,806
  • 13
  • 138
  • 188
1

Use the System.Data.DataRow.IsNull function instead.

if(dr.IsNull("Stage"))
{
 ...
}
David
  • 72,686
  • 18
  • 132
  • 173
0

Below is an example of a nullable data type which you can use to avoid DBNull errors. The example below is not a genuine solution for the issue you have, but is an example of how you can go about solving it. Think of it as learning to fish, instead of being given a fish.

I pulled this from http://msdn.microsoft.com/en-us/library/1t3y8s4s.aspx

class NullableExample
{
    static void Main()
    {
        int? num = null;
        if (num.HasValue == true)
        {
            System.Console.WriteLine("num = " + num.Value);
        }
        else
        {
            System.Console.WriteLine("num = Null");
        }

        // y is set to zero
        int y = num.GetValueOrDefault();

        // num.Value throws an InvalidOperationException if num.HasValue is false
        try
        {
            y = num.Value;
        }
        catch (System.InvalidOperationException e)
        {
            System.Console.WriteLine(e.Message);
        }
    }
}
EastOfJupiter
  • 781
  • 5
  • 11
0

@MarcGravell had the right of it in his comment:

Ignore the exact line number in the stack-trace; the numbers can be slightly off - I see that all the time. Run it in a debugger with break-points instead, or just add extra logging while you nail it down

@Sergey's answer is just plain wrong.

TZHX
  • 5,291
  • 15
  • 47
  • 56