【问题标题】:VB.NET How to correctly loop through a result setVB.NET 如何正确循环遍历结果集
【发布时间】:2019-11-30 18:18:19
【问题描述】:

我在这个网站上查看了许多不同的代码 sn-ps,看起来这些代码会告诉我如何做一些在我掌握了知识后应该相当简单的事情。

我想在数据库表中查询一组值,然后用这些结果填充组合框。

这是我目前所拥有的:

Public Sub getMachines()
    Try

            Dim SQL As String = "SELECT MachineName from machine"


            Form1.machineName.DisplayMember = "Text"
            Dim tb As New DataTable
            tb.Columns.Add("Text", GetType(String))

            Using cn As New MySqlConnection(ConnectionString)
                Using cmd As New MySqlCommand(SQL, cn)

                    For Each cmd As String In cmd
                        'I want to add each value found in the database to "tb.Rows.Add"
                        'tb.Rows.Add(???)
                    Next

                    Form1.machineName.DataSource = tb

                    cn.Open()
                    cmd.ExecuteNonQuery()
                End Using
                cn.Close()
            End Using

    Catch ex As MySqlException
        MsgBox(ex.Message)
    End Try
End Sub

【问题讨论】:

  • Create 带有MySqlDataAdapter.Fillassign it 的DataTable 到组合框。
  • @GSerg,感谢您朝着正确的方向前进。我现在将阅读链接。再次感谢!问题:使用 Fill 方法不需要我在表单上有一个表格,是吗?
  • 一般来说,我们会使用数据绑定而不是循环遍历结果。
  • @JoelCoehoorn,谢谢 Joel,我对这种语言非常迷茫,所以我需要继续阅读。我不知道什么是数据绑定,但我会查一下。感谢您的建议。

标签: vb.net


【解决方案1】:

我的做法和你一样。我使用了 DataTable 的 Load 方法。不必设置列名和类型。列名取自 Select 语句,数据类型由 ADO.net 从前几条记录中推断出来。

幸运的是,DataTable 可以使用 .AsEnumnerable 方法成为 Enumerable。然后我们可以使用 Linq 从 MachineName 列中获取所有值。调用 .ToArray 会导致 Linq 执行。如果您将光标悬停在这一行的名称上,您将看到数据类型是 String()。正是我们需要填充组合框。

DataAccess 类的代码

Private ConnectionString As String = "Your Connection String"

Public Function GetMachineNames() As String()
    Dim tb As New DataTable
    Dim SQL As String = "SELECT MachineName from machine;"
    Using cn As New MySqlConnection(ConnectionString)
        Using cmd As New MySqlCommand(SQL, cn)
            cn.Open()
            dt.Load(cmd.ExecuteReader)
        End Using
    End Using
    Dim names = dt.AsEnumerable().Select(Function(x) x.Field(Of String)("MachineName")).ToArray()
    Return names
End Function

在表单中加载你这样的组合框。

Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    Dim DatAcc As New DataAccess() 
    Dim arr = DatAcc.GetMachineNames()
    machineName.DataSource = arr
End Sub

【讨论】:

  • 归根结底,这对我有用,谢谢你,玛丽!我试图做的是制作一个可以在其他项目中重用的 DataAccess 或 DBAL。我想要一个可以放入其他项目的骨架类,连接字符串是唯一需要更改的东西。这可能吗,还是我必须为我编写的每个进程编写一个连接?
【解决方案2】:

如果您只想将 MachineName 显示在 ComboBox 中,那么只需将其用作 DisplayMember;不要费心创建另一个名为 Text 的列。

Public Sub getMachines()
    Try
        Dim cmd As String = "SELECT MachineName from machine"
        Dim ds As New DataSet()
        Using con As New MySqlConnection(ConnectionString)
            Using da As New MySqlDataAdapter(cmd, con)
                da.Fill(ds)
                With Form1.machineName
                    .DisplayMember = "MachineName"
                    .ValueMember = "MachineName"
                    .DataSource = ds
                End With
            End Using
        End Using
    Catch ex As MySqlException
        MsgBox(ex.Message)
    End Try
End Sub

【讨论】:

  • 感谢 djv。我已经尝试过你的代码 sn-p,我在组合框中看到的是:System.Data.DataViewManagerListItemTypeDescriptor。这没有按预期工作。
  • 另外,我注意到没有循环。不应该有一个循环来处理它在数据库中找到的每个值吗?
  • @NaN 这就是数据绑定的重点。它将控件指向数据列表。您只需要让它知道将使用哪个字段进行显示。抱歉,它不起作用。我是从this answer 翻译过来的。我个人会使用某种 ORM,例如 EF,因为很多工作已经为您完成了。
  • @NaN 查看this answer,这暗示有一个奇怪的错误与 DisplayMember 和 DataSoruce 的设置顺序有关。我通过交换顺序改变了我的答案。试试看。
  • 嗨 djv,感谢您的帮助。我已经尝试过您的编辑,但我没有返回组合框,它是空的。感谢您指出数据绑定以及它如何帮助我。我想在这一点上我会朝那个方向看。
【解决方案3】:

我将展示一些示例,包括使用参数,因为这很重要。

首先,快速翻译运行现有查询并循环遍历结果:

Public Sub getMachines()
    Try    
        Dim SQL As String = "SELECT MachineName from machine"

        Using cn As New MySqlConnection(ConnectionString), _
              cmd As New MySqlCommand(SQL, cn)

            cn.Open()
            Using rdr As MySqlDatareader = cmd.ExecuteReader
                While rdr.Read()
                    Form1.machineName.Items.Add(rdr("MachineName"))
                End While
            End Using
        End Using
    Catch ex As MySqlException
        MsgBox(ex.Message)
    End Try
End Sub

但对于这种方法,更好的做法是隔离 UI 的数据访问。这个方法应该返回结果给调用者,调用者可以决定如何处理它们。所以我将展示两种方法:一种是获取数据,另一种是循环并设置组合框:

Private Function GetMachines() As DataTable
    'No try/catch needed here. Handle it in the UI level, instead
    Dim SQL As String = "SELECT MachineName from machine"
    Dim result As New DataTable

    Using cn As New MySqlConnection(ConnectionString), _
          cmd As New MySqlCommand(SQL, cn),
          da As New MySqlDataAdapter(cmd)

          da.Fill(result)
   End Using
   Return result
End Function

Public Sub LoadMachines()
    Try
        For Each item As DataRow in getMachines().Rows
            Form1.machineName.Items.Add(item("MachineName"))
        Next
    Catch ex As MySqlException
        MsgBox(ex.Message)
    End Try
End Sub

或者,我们可以使用 DataBinding:

Private Function GetMachines() As DataTable
    Dim SQL As String = "SELECT MachineName from machine"
    Dim result As New DataTable

    Using cn As New MySqlConnection(ConnectionString), _
          cmd As New MySqlCommand(SQL, cn),
          da As New MySqlDataAdapter(cmd)

          da.Fill(result)
   End Using
   Return result
End Function

Public Sub LoadMachines()
    Try
        Form1.machineName.DisplayMember = "FirstName";  
        Form1.machineName.ValueMember = "City" 
        Form1.machineName.DataSource = GetMachines()  
    Catch ex As MySqlException
        MsgBox(ex.Message)
    End Try
End Sub

如果你想使用过滤器,你可以这样做(注意重载):

Private Function GetMachines(ByVal machineFilter As String) As DataTable
    Dim SQL As String = "SELECT MachineName from machine WHERE MachineName LIKE @Filter"

    Dim result As New DataTable

    Using cn As New MySqlConnection(ConnectionString), _
          cmd As New MySqlCommand(SQL, cn),
          da As New MySqlDataAdapter(cmd)

        'Match the MySqlDbType to your actual database column type and length
        cmd.Parameters.Add("@Filter", MySqlDbType.VarString, 30).Value = machineFilter

       da.Fill(result)
   End Using
   Return result
End Function

Private Function GetMachines(ByVal machineFilter As String) As DataTable
    Return GetMachines("%")
End Function

这样的查询参数非常重要,如果您在旧平台上进行字符串连接来完成这种事情,那么您在那儿做了非常糟糕的事情 ,也是。

最后,让我们来看看吧。很多时候,您真的不想将整个结果集加载到 RAM 中,就像 DataTable 所做的那样。那可能很糟糕。相反,您希望能够将结果流式传输到内存中,并且一次只能使用一个,从而最大限度地减少 RAM 的使用。在这些情况下,您可以使用DataReader... 但从Using 块(这很重要)中返回一个DataReader 对象并不能很好地工作。为了解决这个问题,我们可以使用函数式编程概念和高级语言特性:

Private Iterator Function GetMachines(ByVal machineFilter As String) As IEnumerable(Of String)
    Dim SQL As String = "SELECT MachineName from machine WHERE MachineName LIKE @Filter"

    Using cn As New MySqlConnection(ConnectionString), _
          cmd As New MySqlCommand(SQL, cn)

        'Match the MySqlDbType to your actual database column type and length
        cmd.Parameters.Add("@Filter", MySqlDbType.VarString, 30).Value = machineFilter
        cn.Open()
        Using rdr As MySqlDatareader = cmd.ExecuteReader
            While rdr.Read()
                Dim result As String = rdr("MachineName")
                Yield Return result
            End While
        End Using
   End Using
   Return result
End Function

Private Function GetMachines() As IEnumerable(Of String)
    Return GetMachines("%")
End Function

【讨论】:

  • 谢谢你,乔尔,这对理解应该如何做非常有帮助。再次谢谢你。我现在就看看这个。
  • 乔尔,在我离开之前,我想让你知道我尝试了你的数据绑定 sn-p。如果我要学习这种语言,那么我不妨学习最佳实践,正如您所指出的那样。至于 try/catch 块,我知道最好不要在模型中使用它们。感谢您指出我的错误。我不知道为什么,但是您的数据绑定 sn-p 将它放在组合框中,而不是我期望的值:System.Data.DataViewManagerListItemTypeDescriptor。使用上面的 djv 代码,我也得到了同样的行为。
  • 你可能需要一个“ToString()”调用,或者类似的。试试我的最后一个例子,它处理数据方法中的 Object => String 转换。
  • 哇,乔尔,非常感谢您花这么多时间来解释这一点!你超越了,谢谢!我尝试了您的最后一次编辑,但无法使其正常工作。但是,我确实从您的每个示例中获得了很多信息。我知道用我熟悉的语言编写这样的代码的正确方法,但是使用 VB.NET,我很难爬行。就是说,谢谢你的解释!
猜你喜欢
  • 1970-01-01
  • 2019-02-18
  • 2010-12-17
  • 1970-01-01
  • 2013-09-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多