【问题标题】:Avoid NullReferenceException避免 NullReferenceException
【发布时间】:2010-12-17 19:34:43
【问题描述】:

我对 .NET 编程相当陌生。我正在尝试检查数据库表中是否有设置,如果没有,请创建一些默认设置。问题是,当没有设置时,我需要使用数据读取器进行两次调用,它一直给我带来问题。

我最初只使用一个数据读取器,但做了两个尝试解决我的问题,没有工作。
然后我尝试关闭数据读取器,但我收到错误,因为它返回了一个空引用。

如果我尝试关闭它,我会遇到问题,如果我不关闭它,下一个会给我一个错误,提示此连接上已经有一个打开的数据读取器需要关闭。谁能告诉我如何重构代码以使其正常工作(最好使用一个数据读取器)?

我还尝试将 reader.close() 放在另一组 try catch 中,虽然这使我能够捕获错误,但它仍然没有关闭 datareader,所以我不知所措。

Private Sub Get_Initial_Settings()
    Dim reader1 As MySqlDataReader = Nothing, reader2 As MySqlDataReader = Nothing
    Dim cmd As New MySqlCommand("SELECT depot, size, roc_family, wil_family, ast_family, met_family, ric_family, view FROM vb_dashboard.user_preferences WHERE " & GetUserName() & "", conn)
    Dim hasSettings As Boolean

    'Get Personal Settings or initiate them if necessary
    Try
        reader1 = cmd.ExecuteReader
        hasSettings = True
        MessageBox.Show("Your user settings show you have a selected depot of " & reader1(0).ToString)
    Catch ex As Exception
        'No settings exist, set some up
        MessageBox.Show("You have no settings for this program yet")
        hasSettings = False
    Finally
        reader1.Close()
    End Try

    'User has no preferences, Create some
    'First, create a list of depots to select from and add it to a combobox
    If (hasSettings = False) Then
        Try

            cmd.CommandText = "SELECT depot FROM vb_dashboard.depots ORDER BY depot"
            reader2 = cmd.ExecuteReader
            While (reader2.Read)
                dlgSelectDepot.cbDepotSelect.Items.Add(reader2.GetString(0))
            End While
            'Now show the dialog box to initiate a depot setting
            Me.Hide()
            dlgSelectDepot.Show()
            Me.Show()
            If (dlgSelectDepot.DialogResult = Windows.Forms.DialogResult.Cancel) Then
                Me.Close()
            End If
            cmd.CommandText = "INSERT INTO vb_database.user_preferences SET user='" & GetUserName.ToUpper & "', depot='Rochester'"
            cmd.ExecuteNonQuery()
        Catch ex As Exception
            MessageBox.Show("An error has occurred: " & ex.Message)
        Finally
            reader2.Close()
        End Try
    End If

End Sub

【问题讨论】:

    标签: vb.net visual-studio-2008 mysqldatareader


    【解决方案1】:

    您正在重新使用您的 cmd 对象。实际上,您将每个阅读器设置为与命令对象相同的连接。您应该创建 2 个不同的命令对象,它们都有自己的数据库连接。

    另一种选择是从第一个数据读取器获取您需要的信息并存储在数据表中(使用 MySqlDataAdapter)。如果该信息不可用,请关闭该连接,使用新命令对象创建一个新连接。这大概就是我要走的方向。

    编辑

    您确实需要使用New SqlConnection() 并让操作系统来处理。

    【讨论】:

    • 感谢您的快速回复。所以我必须为每次调用数据库创建一个新连接?这将是很多连接。有什么方法可以维持一个连接并重复使用它?
    • 您可以在一个连接上进行多次调用,但我认为这是不好的做法,因为操作系统无法管理它们。建立连接不是资源密集型的。我拨打的每个电话都包含在Using 子句中。我可以在任何给定时刻轻松地打开和关闭 7 或 8 个。
    • 酷,我认为继续与 Using 子句建立联系是不好的做法。我宁愿使用 Using 并避免 Try/Catch 一起使用。谢谢,我会努力的
    • Using 子句是你最好的朋友。我已经养成了查看我想使用的类并确定它是否实现IDisposable 的习惯,如果实现了,那么我首先考虑是否应该使用Using
    • 我认为为您要执行的每条 SQL 语句重新打开连接是不必要或理想的。您只需要(并且总是)在成功创建对象后正确处理它们。使用会使这更容易,但如果您还需要异常处理,则必须将其嵌套在 Try/Catch 中,而 Try/Catch/Finally 可以在一个级别上完成所有操作。
    【解决方案2】:

    问题是在您的第二个尝试块中,您正在执行一个仍然具有打开阅读器的命令。我使用使用积木来帮助它们保持直线,例如:

    
    Using cn As new DbConnection(connectionString)
     cn.Open()
     Using cmd As DbCommand = cn.CreateCommand()
      'first command
      cmd.CommandText = "SELECT depot FROM vb_dashboard.depots ORDER BY depot" 
      Using dr As DbDataReader = cmd.ExecuteReader()
       While dr.Read()
        dlgSelectDepot.cbDepotSelect.Items.Add(reader2.GetString(0))
       End While
       dr.Close()
      End Using
      '
      'next command
      cmd.CommandText = "INSERT INTO vb_database.user_preferences SET user='" & GetUserName.ToUpper & "', depot='Rochester'"
      cmd.ExecuteNonQuery()
     End Using
     cn.Close()
    End Using
    

    【讨论】:

    • 我认为这个解决方案的问题是没有异常处理,因此代码无法检测到用户设置何时尚未初始化。
    【解决方案3】:

    我认为问题在于您有两个潜在的问题原因,并且一次只能使用您使用的代码类型解决一个。以下是两种可能性:

    1. 尚无用户设置。
    2. 您正在为多个查询重复使用相同的命令和连接对象。

    使用您当前拥有的代码,我认为您已经解决了问题 #2,但重新引入了问题 1。如果尚不存在用户设置,则永远不会创建数据读取器,因为执行命令失败。因此,当您尝试关闭数据读取器时,您会收到错误消息。当代码没有关闭数据读取器时,您解决了问题#1,但没有解决问题#2。我认为有几个更好的方法可以解决这个问题:

    1. 寻找更好的方法来检测用户设置是否存在。例如,SELECT COUNT(*) FROM sys.objects where name = 'user_preferences'
    2. 在尝试关闭之前检查“If reader1 IsNot Nothing”。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-08-17
      • 1970-01-01
      • 2014-07-23
      • 2023-03-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多