【问题标题】:DataAdapter is disposed before reaching "End Using"DataAdapter 在到达“结束使用”之前被处理
【发布时间】:2016-11-10 17:14:33
【问题描述】:

我知道我应该始终处置 DataAdapter 实例。在大多数情况下,我会在关闭连接后立即处理它,但在用户将修改 DataTable 项目(显示在 ListBox 或 DataGridView 中)的情况下,我会创建 DataAdapter,使用它来填充 DataTable,但不要处理它直到用户点击调用DataAdapter.Update(DataTable)Save...不是我的主要问题,但这是正确的方法吗?

回到主要问题,我有这两个功能:

Public Function LoadCompaniesDT(ByRef dtCompanies As DataTable) As Boolean
    Using daCompanies As MySqlDataAdapter = Nothing
        Return LoadCompaniesDT(daCompanies, dtCompanies)
    End Using
End Function

Public Function LoadCompaniesDT(ByRef daCompanies As MySqlDataAdapter, ByRef dtCompanies As DataTable) As Boolean
    Dim sql As String = "SELECT * FROM companies"
    Return LoadDT(daCompanies, dtCompanies, sql, Res.CompaniesFailedMsgBody)
End Function

他们习惯于调用 LoadDT 来填充 DataTable,因此我可以选择是否传递 DataAdapter。

现在我对一些事情感到困惑:当使用第一个 LoadCompaniesDT 函数时,daCompanies 在到达 End Using 之前就被释放了。像这样:

Public Function LoadCompaniesDT(ByRef dtCompanies As DataTable) As Boolean
    Using daCompanies As MySqlDataAdapter = Nothing
        Dim tmp As Boolean = LoadCompaniesDT(daCompanies, dtCompanies)
        Console.WriteLine(daCompanies Is Nothing) ' ==> True!!
        Return tmp
    End Using
End Function

注意:如果我使用Dim daCompanies 而不是Using daCompanies,那么daCompanies Is Nothing 将返回False。


LoadDT功能码:

Private Function LoadDT(ByRef da As MySqlDataAdapter, ByRef dt As DataTable,
                                                      ByVal sqlQuery As String,
                                                      ByVal errorText As String) As Boolean
    Dim connStr As String = String.Format("server={0}; port={1}; user id={2}; password={3}; database={4}",
                                          DbServer, DbServerPort, DbUserName, DbPassword, DatabaseName)
    Dim conn As MySqlConnection = New MySqlConnection(connStr)
    Dim cmd As MySqlCommand = New MySqlCommand

    Try
        conn.Open()

        cmd.CommandType = CommandType.Text
        cmd.CommandText = sqlQuery
        cmd.Connection = conn

        da = New MySqlDataAdapter(cmd)
        dt = New DataTable
        da.Fill(dt)

        Return True
    Catch ex As Exception
        MessageBox.Show(errorText, Res.ServerError, MessageBoxButtons.OK, MessageBoxIcon.Error)
        Return False
    Finally
        cmd.Dispose()
        cmd = Nothing
        conn.Close()
        conn.Dispose()
    End Try
End Function

【问题讨论】:

  • 你应该把标题改成ByRef,因为这是这个问题的核心

标签: vb.net idisposable dataadapter


【解决方案1】:

更新:你是对的,如果在 Using 语句中使用 ByRef 传递的实例,则不会从方法中返回初始化的 MySqlDataAdapter。这些变量是只读的。在 C# 中,您会收到 this 有意义的编译器错误:

错误 CS1657 无法将“daCompanies”作为 ref 或 out 参数传递 因为它是一个“使用变量”

记录在案here:

编译器错误CS1657

不能将“参数”作为参考或输出参数传递,因为“原因” 当变量作为 ref 或 out 参数传递时会发生此错误 在该变量是只读的上下文中。只读上下文 包括 foreach 迭代变量、使用变量和固定 变量。

在 VB.NET 中,您可以这样做(因此编译器会忽略它,这几乎是一个错误),但之后不会初始化该变量。但如下所述,无论如何您都不应该使用这种方法。


根据另一个问题:

如果您查看MSDN 上的示例,您会发现微软也没有处理数据适配器。所以真的没有必要。话虽如此,最好的做法是对任何实现 IDisposable 的东西使用 Using 语句。

DataAdapter 不是一个昂贵的对象,它不包含非托管资源(如连接)。因此,无论您需要什么,都可以从中创建一个新实例。而且您不需要处置它,但这是一个实现细节,将来可能会改变或在 DbDataAdapter 的不同实现中发生变化,因此处置它仍然是最佳实践,最好使用 Using-statement。

我不会使用您的方法,因为您将 sql 字符串传递给通常会导致 sql 注入漏洞的方法。而是使用 sql 参数。

例如:

Private Function LoadDT() As DataTable
    Dim tbl As New DataTable()
    'Load connection string from app.config or web.config
    Dim sql As String = "SELECT * FROM companies" ' don't use * but list all columns explicitely
    Using conn As New MySqlConnection(My.Settings.MySqlConnection)
        Using da = New MySqlDataAdapter(sql, conn)
            da.Fill(tbl)
        End Using
    End Using
    Return tbl
End Function

我不会传递errorText ByRef,而是使用像log4net 这样的日志框架。

【讨论】:

  • 是的,这就是我从this 问题中得到的印象。那么为什么它会在到达Using 语句的末尾之前被处理掉呢?
  • 我明白了。谢谢你的努力,确实有帮助:)
  • 我刚刚注意到您关于使用参数的说明,是的,我这样做了,但是在这个函数中我只是加载整个表(没有WHERE clause),这有问题吗?另外我不明白SELECT * FROM 会导致什么?
  • @GeniuSBraiN:我不使用参数,因为在这种情况下不需要它们。但是通过允许 sql-string 作为参数,您也允许:SELECT * FROM Tbl WHERE ID='';DELETE FROM Tbl。因此,最好不要通过连接字符串或传递它们来构建 sql 查询。一个 sql 查询应该始终是一个字符串常量。例如:SELECT Col1 FROM tbl WHERE ID=@ID
  • 在这里您可以找到更多关于为什么SELECT * 在生产代码中是bad habit to kick 的信息。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-05-11
  • 1970-01-01
  • 1970-01-01
  • 2015-06-19
  • 1970-01-01
相关资源
最近更新 更多