从ComboBox选择

时间:2016-02-03 18:58:02

标签: sql vb.net error-handling

我对数据库值以及如何确定用户在某个时刻更改过的值的ID有疑问。

当前设置时,会有一个从数据集中填充的组合框,以及后续文本框,其文本应由从该组合框中选择的值确定。

因此,举个例子,您可以选择公司A'从组合框中,我希望数据集中该公司行的所有相应信息填充文本框(名称=公司A,地址= 123 ABC St.等)

我能够很好地填充组合框。但是,当我更改组合框的索引时,才会发生此特定错误:

  

未处理的类型' System.Data.OleDb.OleDbException'   发生在System.Data.dll

中      

其他信息:标准表达式中的数据类型不匹配。

以下是相应的代码:

Imports System.Data.OleDb
Public Class CustomerContact

    Dim cn As New OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=|datadirectory|\CentralDatabase.accdb;")
    Dim da As New OleDbDataAdapter()
    Dim dt As New DataTable()

    Private Sub CustomerContact_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        cn.Open()
        da.SelectCommand = New OleDbCommand("select * from Customers", cn)
        da.Fill(dt)

        Dim r As DataRow
        For Each r In dt.Rows
            cboVendorName.Items.Add(r("Name").ToString)
            cboVendorName.ValueMember = "ID"
        Next
        cn.Close()
    End Sub

    Private Sub cboVendorName_SelectedIndexChanged(sender As Object, e As EventArgs) Handles cboVendorName.SelectedIndexChanged
        cn.Open()
        da.SelectCommand = New OleDbCommand("select * from Customers WHERE id='" & cboVendorName.SelectedValue & "'", cn)
        da.Fill(dt)
            Dim r As DataRow
            For Each r In dt.Rows
            txtNewName.Text = "Name"
            txtAddress.Text = "Address"
            Next
            cn.Close()
    End Sub

错误发生在第二行da.Fill(dt)的第24行。现在很明显,从异常中我知道我将错误的数据类型发送到OleDbCommand,不幸的是,当涉及到诸如此类的SQL命令时,我是一个新手。另外请记住,我甚至无法测试第二个For循环,它应该将客户信息填充到文本框中(为方便起见,我只复制了前两个文本框,其中总共有九个文本框) 。我认为我可以使用If语句来确定是否已经读取了行,并从那里填充了文本框,但是当我能够访问它时我会跳过这个障碍。

非常感谢任何指导或建议。我再次成为管理数据库的新手,所涉及的代码与项目有关,我目前的实习是让我为他们写的。

1 个答案:

答案 0 :(得分:1)

由于您已经在DataTable中拥有该表中的所有数据,因此根本不需要运行查询。表单加载设置(如果必须):

' form level object:
Private ignore As Boolean
Private dtCust As New DataTable
...
Dim SQL As String = "SELECT Id, Name, Address, City FROM Customer"
Using dbcon = GetACEConnection()
    Using cmd As New OleDbCommand(SQL, dbcon)

        dbcon.Open()
        dtCust.Load(cmd.ExecuteReader)
    End Using
End Using

' pk required for Rows.Find
ignore = True
dtCust.PrimaryKey = New DataColumn() {dtCust.Columns(0)}
cboCust.DataSource = dtCust
cboCust.DisplayMember = "Name"
cboCust.ValueMember = "Id"
ignore = False

忽略标志将允许您忽略由于DataSource被设置而触发的第一个更改。这将在Display和Value成员设置之前触发。

初步问题/变更:

  • 意图创建,使用和处置连接。对于Access来说,这稍微不那么真实,但仍然是一个很好的做法。 GetACEConnection方法不是在任何地方连接字符串,而是为我创建它们。代码is in this answer
  • 为了经济利益而不是DataAdapter只是填表,我用了一个读者
  • Using语句也会创建和处置Command对象。通常,如果对象具有Dispose方法,请将其放在Using块中。
  • 我拼写了SQL的列。如果您不需要所有列,请不要问所有列。指定它们还允许我控制顺序(在DGV中显示顺序,按索引引用列 - dr(1) = ... - 除其他外)。

重要的是,我不是将项目添加到cbo,而是使用DataTable作为组合的DataSource。没有ValueMemberDataSource不会做任何事情 - 这是您遇到的核心问题。没有DataSource,因此SelectedValue始终为Nothing

然后在SelectedValueChanged事件:

Private Sub cboCust_SelectedValueChanged(sender As Object, 
              e As EventArgs) Handles cboCust.SelectedValueChanged

    ' ignore changes during form load:
    If ignore Then Exit Sub

    Dim custId = Convert.ToInt32(cboCust.SelectedValue)
    Dim dr = dtCust.Rows.Find(custId)

    Console.WriteLine(dr("Id"))
    Console.WriteLine(dr("Name"))
    Console.WriteLine(dr("Address"))
End Sub

使用所选值,我在DataTable中找到相关行。查找返回DataRow(或Nothing),以便我可以访问所有其他信息。结果:

  

4
  戈蒂埃
  sdfsdfsdf

另一种选择是:

Dim rows = dtCust.Select(String.Format("Id={0}", custId))

这将返回符合条件的DataRow数组。当目标列是文本时,String.Format很有用。此方法不需要上面的PK定义:

Dim rows = dtCust.Select(String.Format("Name='{0}'", searchText))

有关详细信息,请参阅: