Question

I have the follwoing code that performs a query and returns a result. However, I looked around and found some examples to take care of null values but I get an error: "Invalid attempt to read when no data is present." I also got the error: "Conversion from type 'DBNull' to type 'Decimal' is not valid."

Can someone help me out with this code to prevent null values from crashing my program?

Private Sub EFFICIENCY_STACKRANK_YTD(ByVal EMPLOYEE As String)

    Dim queryString As String = "SELECT " & _
    " (SELECT CAST(SUM(TARGET_SECONDS) AS DECIMAL)/ CAST(SUM(ROUTE_SECONDS) AS DECIMAL) FROM dbo.APE_BUSDRIVER_MAIN WITH(NOLOCK) WHERE APE_AREA_OBJID = " & lblAreaOBJID.Text & " AND EMPLOYEE_NAME = '" & EMPLOYEE & "' AND YEAR_TIME = '" & cbYear.Text & "' AND ACTIVE = 1) AS RESULT1" & _
    " FROM dbo.APE_BUSDRIVER_MAIN "


    Using connection As New SqlConnection(SQLConnectionStr)
        Dim command As New SqlCommand(queryString, connection)
        connection.Open()
        Dim reader As SqlDataReader = command.ExecuteReader()

        If reader.Read Then
            RESULT1 = reader("RESULT1")
        Else
            RESULT1 = 0
        End If

    End Using
End Sub
Was it helpful?

Solution

You have opened the reader, but have not asked it to actually read anything.

After this line:

Dim reader As SqlDataReader = command.ExecuteReader()

add

If reader.Read() Then

and wrap the result reading into this if statement, i.e.

If reader.Read() Then
    Dim index As Integer = reader.GetOrdinal("RESULT1")
    If reader.IsDBNull(index) Then
        RESULT1 = String.Empty
    Else
        RESULT1 = reader(index)
    End If
End If

Note that this works because your SQL should only return a single record. In the event that you were reading multiple records, you would need to call the Read statement in a loop until there were no more records, i.e.

Do While reader.Read()

Loop

OTHER TIPS

I wanted to provide another, more-advanced, answer as an option. Many classes can be extended in .NET like this.

If you are regularly performing "Is NULL" checks like this in your applications, you can choose to extend the DataReader class once to have additional functions available everywhere in your application. Here is an example that creates an extension called "ReadNullAsString()" onto the data reader class. This makes a function that always returns String.Empty when a DbNull is encountered.

Part 1, place this module code in a new class file in App_Code if application is a website, otherwise place where ever you prefer. There are two overloads, one for the field's ordinal position (aka index), and one for the field's ColumnName.

Public Module DataReaderExtensions

    ''' <summary>
    ''' Reads fieldName from Data Reader. If fieldName is DbNull, returns String.Empty.
    ''' </summary>
    ''' <returns>Safely returns a string. No need to check for DbNull.</returns>
    <System.Runtime.CompilerServices.Extension()> _
    Public Function ReadNullAsEmptyString(ByVal reader As IDataReader, ByVal fieldName As String) As String
        If IsDBNull(reader(fieldName)) Then
            Return String.Empty
        Else
            Return reader(fieldName)
        End If
        Return False
    End Function

    ''' <summary>
    ''' Reads fieldOrdinal from Data Reader. If fieldOrdinal is DbNull, returns String.Empty.
    ''' </summary>
    ''' <returns>Safely returns a string. No need to check for DbNull.</returns>
    <System.Runtime.CompilerServices.Extension()> _
    Public Function ReadString(ByVal reader As IDataReader, ByVal fieldOrdinal As Integer) As String
        If IsDBNull(reader(fieldOrdinal)) Then
            Return ""
        Else
            Return reader(fieldOrdinal)
        End If
        Return False
    End Function

End Module

Step 2, call the new extension like so:

' no need to check for DbNull now, this functionality is encapsulated in the extension module.
RESULT1 = reader.ReadNullAsEmptyString(index)
'or
RESULT1 = reader.ReadNullAsEmptyString("RESULT1")
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top