【问题标题】:How can I get my datatable to update - vb.net?如何让我的数据表更新 - vb.net?
【发布时间】:2019-12-19 14:54:06
【问题描述】:
Dim strSQL as string = "select ScreenName, Status from ScreenCheckDuplicates where ScreenName='" & ScreenName & "'"
Dim aObj as new SqlDataAdapter(strSQL,conn)

dim dtObj as New DataTable
aObj.Fill(dtObj)

If dtObj.Rows.Count > 0 Then
   dtObj.Rows(0)("Status") = Status
   dtObj.AcceptChanges()
Else
   Dim drNew as DataRow = dtObj.NewRow()
   drNew("ScreenName") = ScreenName
   drNew("Status") = Status
   dtObj.Rows.Add(drNew)
   dtObj.AcceptChanges()
End If

如果 Rows.Count > 0(屏幕名称在表中),状态将不会更新。

当我从 DataTable 中删除所有行以便运行 Else 子句时,没有添加新行。

所以...我一定想念它是如何更新表格的,需要一些帮助。我打赌这很简单,我只是想念它:(

【问题讨论】:

  • 您已经创建了一个SqlDataAdapter,但没有指定任何方式让它使用您的更改更新数据库。你只为它提供了一个SELECT 声明
  • 您是否使用该查询检索表的 PrimaryKey? (也许是屏幕名称?)
  • 这个小表没有主键,但如果我要创建一个,它会是 ScreenName,是的。
  • 是的,添加主键总是一个好主意。 (从我的回答中可以看出,您可以删除很多代码来更新您的表格)

标签: vb.net datatable


【解决方案1】:

虽然您已经使用SELECT 命令创建了SqlDataAdapter,以便它可以获取数据,但您还没有告诉它如何获取UPDATEINSERT 数据。

这些需要显式添加到SqlDataAdapter,以便它了解如何执行这些数据更新。

我已经模拟了一个如何执行此操作的示例,但它可能不起作用,因为确切的 SQL 语法将取决于您的表定义:

Dim aObj As New SqlDataAdapter(strSQL, conn)

' Create the update command
aObj.UpdateCommand = New SqlCommand("UPDATE ScreenCheckDuplicates SET Status = ? WHERE ScreenName = ?")
aObj.UpdateCommand.Parameters.Add("Status", SqlDbType.VarChar)
aObj.UpdateCommand.Parameters.Add("ScreenName", SqlDbType.VarChar)

' Create the insert command
aObj.InsertCommand = New SqlCommand("INSERT INTO ScreenCheckDuplicates VALUES (?, ?)")
aObj.InsertCommand.Parameters.Add("Status", SqlDbType.VarChar)
aObj.InsertCommand.Parameters.Add("ScreenName", SqlDbType.VarChar)

This Microsoft article 描述了您可以用来实现目标的精确方法。

【讨论】:

    【解决方案2】:

    首先,不要连接字符串来创建sql命令。如果您的字符串包含单引号,这会导致 Sql 注入攻击和语法错误。相反,您应该使用参数

    Dim strSQL as string = "select ScreenName, Status 
                            from ScreenCheckDuplicates 
                            where ScreenName=@name"
    Dim aObj as new SqlDataAdapter(strSQL,conn)
    aObj.SelectCommand.Parameters.Add("@name", SqlDbType.NVarChar).Value = ScreenName 
    dim dtObj as New DataTable
    aObj.Fill(dtObj)
    

    现在一个常见的错误是认为AcceptChanges 更新了数据库表。这是错误的,AcceptChanges 将 DataTable 对象中每一行的RowState 属性从"DataRowState.Modified"(或其他值)更改为"DataRowState.Unchanged",在此调用之后,无法知道哪些行已更改,也没有简单的方法更新您的数据库。所以删除那行

    If dtObj.Rows.Count > 0 Then
       dtObj.Rows(0)("Status") = Status
    Else
       Dim drNew as DataRow = dtObj.NewRow()
       drNew("ScreenName") = ScreenName
       drNew("Status") = Status
       dtObj.Rows.Add(drNew)
    End If
    

    此时您已准备好将更改提交到数据库。您可以使用 SqlCommandBuilder 对象创建更新行所需的 sql 命令。但这只有在您检索到数据库表的主键时才有效。
    所以假设ScreenName是主键那么你可以写

    Dim builder As SqlCommandBuilder = new SqlCommandBuilder(aObj)
    aObj.Update(dtObj)
    

    【讨论】:

      【解决方案3】:

      我假设 ScreenName 是 ScreenCheckDuplicates 表的主键。更新表的方法使用主键。

      将您的数据库对象保存在本地,以便您可以控制它们是否已关闭和处置。 Using...End Using blocks 会为你处理这个问题,即使出现错误。

      总是使用参数来避免 Sql 注入。我不得不猜测 SqlDbType 和字段大小。检查您的数据库中的实际值并相应地调整代码。

      当您使用 DataAdapter 时,您需要提供所需的命令。命令生成器将为您执行此操作。在对 DataAdapter 使用 Update 方法之前,不要在 DataTable 上调用 .AcceptChanges。

      Private Sub OpCode(ScreenName As String, Status As String)
          Using conn As New SqlConnection("Your connection string"),
              cmd As New SqlCommand("select ScreenName, Status from ScreenCheckDuplicates where ScreenName= @ScreenName", conn)
              cmd.Parameters.Add("@ScreenName", SqlDbType.VarChar, 100).Value = ScreenName
              Using aObj As New SqlDataAdapter(cmd)
                  Dim dtObj As New DataTable
                  aObj.Fill(dtObj)
                  Dim cb As New SqlCommandBuilder(aObj)
                  If dtObj.Rows.Count > 0 Then
                      dtObj.Rows(0)("Status") = Status
                      cb.GetUpdateCommand()
                  Else
                      Dim drNew As DataRow = dtObj.NewRow()
                      drNew("ScreenName") = ScreenName
                      drNew("Status") = Status
                      dtObj.Rows.Add(drNew)
                      cb.GetInsertCommand()
                  End If
                  aObj.Update(dtObj)
                  dtObj.AcceptChanges()
              End Using
          End Using
      End Sub
      

      以下替代方法要好一些,因为它只需要对数据库进行一次点击。

      Private Sub BetterWay(ScreenName As String, Status As String)
          Dim strSql = "If EXISTS(SELECT ScreenName, Status FROM ScreenCheckDuplicates where ScreenName= @ScreenName)
              UPDATE ScreenCheckDuplicates SET Status = @Status WHERE ScreenName = @ScreenName
              Else
              INSERT INTO ScreenCheckDuplicates ScreenName, Status VALUES (@ScreenName, @Status)"
          Using cn As New SqlConnection("Your connection string"),
              cmd As New SqlCommand(strSql, cn)
              cmd.Parameters.Add("@ScreenName", SqlDbType.VarChar, 100).Value = ScreenName
              cmd.Parameters.Add("@Status", SqlDbType.VarChar, 50).Value = Status
              cn.Open()
              cmd.ExecuteNonQuery()
          End Using
      End Sub
      

      【讨论】:

        猜你喜欢
        • 2016-07-15
        • 1970-01-01
        • 1970-01-01
        • 2023-03-15
        • 2014-02-05
        • 1970-01-01
        • 2018-07-03
        • 1970-01-01
        • 2010-12-04
        相关资源
        最近更新 更多