如何在VB.net中处理SqlDataReader的空值

5
我有以下代码,可以执行查询并返回结果。然而,我查看了一些解决null值的例子,但是我却遇到了错误:“无效的尝试读取不存在的数据。”我还遇到了这个错误:“从类型 'DBNull' 转换为类型 'Decimal' 不是有效的。”
有人能帮我修改这段代码,防止程序因null值崩溃吗?
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

阅读我对你其他问题的回答。那里的代码已经有效地处理了这个问题。 - Joel Coehoorn
2个回答

10
您已经打开了读取器,但还没有要求它实际读取任何内容。
在这行代码之后:
Dim reader As SqlDataReader = command.ExecuteReader()

添加

If reader.Read() Then

并将结果读取包装到此if语句中,即

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

请注意,这仅适用于SQL只返回单个记录的情况。如果您正在读取多个记录,则需要在循环中调用“Read”语句,直到没有更多记录为止。即:
Do While reader.Read()

Loop

10

我想提供另一个更高级的选项作为答案。在.NET中,许多类都可以通过这种方式进行扩展。

如果您经常在应用程序中执行像这样的“Is NULL”检查,可以选择一次性扩展DataReader类,以便在应用程序的任何地方都有可用的其他函数。以下是一个示例,它创建了一个名为“ReadNullAsString()”的扩展,将其添加到数据读取器类中。这将创建一个函数,当遇到DbNull时始终返回String.Empty。

第一部分:如果应用程序是网站,则将此模块代码放置在App_Code中的新类文件中;否则,请将其放置在任何您喜欢的位置。有两个重载,一个是字段的序数位置(也称为索引),另一个是字段的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

第二步,像这样调用新的扩展:

' no need to check for DbNull now, this functionality is encapsulated in the extension module.
RESULT1 = reader.ReadNullAsEmptyString(index)
'or
RESULT1 = reader.ReadNullAsEmptyString("RESULT1")

非常好!谢谢你也! - Joseph.Scott.Garza

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接