DataAdapter在到达"结束使用"

时间:2016-07-08 07:49:33

标签: vb.net idisposable dataadapter

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

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

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

他们习惯于调用填充DataTable的LoadDT,因此我可以选择是否传递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

1 个答案:

答案 0 :(得分:1)

更新:您是对的,如果private void ButtonBase_OnClick(object sender, RoutedEventArgs e) { ViewModel = new ViewModel(); ViewModel.Text = "x:Bind does not work"; this.Bindings.Update(); } 传递的实例用于某个方法,您将无法从方法中获得初始化MySqlDataAdapter ByRef - 声明。这些变量是只读的。在C#中,您得到this有意义的编译器错误:

  

错误CS1657无法通过' daCompanies'作为ref或out参数   因为它是一个使用变量'

它已记录here

  

编译器错误 CS1657

     

无法通过'参数'作为参考或出局的论据因为'原因''   当变量作为ref或out参数传递时,会发生此错误   在该变量是只读的上下文中。只读上下文   包括foreach迭代变量,使用变量和修复   变量

在VB.NET中你可以这样做(所以编译器会忽略它,这几乎是一个bug)但是之后没有初始化变量。但如下所述,你不应该使用这种方法。

根据另一个问题:

如果您查看MSDN上的示例,您会发现微软也没有配置数据适配器。所以它没有必要。话虽如此,对于实现Using的任何内容,使用Using语句始终是最佳做法。

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

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

例如:

Using

不是传递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,而是使用log4net等日志框架。