简体   繁体   中英

How can I get my datatable to update - vb.net?

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

With Rows.Count > 0 (The ScreenName is in the Table), the Status will not update.

When I removed all rows from the DataTable such that the Else clause would run, No new row was added.

So... I must be missing how it is updating the table and need a bit of help. I'm betting it is pretty simple and I'm just missing it :(

Although you have created the SqlDataAdapter with SELECT command so it can fetch data, you have not told it how to UPDATE or INSERT data.

These need to be explicitly added to the SqlDataAdapter so that it understands how to perform these data updates.

I have mocked up an example of how to do this but it may be non-functional as the exact SQL syntax will depend upon your table definition:

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 describes the precise method you can use to achieve your aim.

First of all, do not concatenate strings to create an sql command. This leads to Sql Injection attacks and to syntax errors if your string contains a single quote. Instead you should use parameters

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)

Now a common error is to think that AcceptChanges updates the database table. This is wrong, AcceptChanges changes the RowState property for every row in your DataTable object from "DataRowState.Modified" (or other values) to "DataRowState.Unchanged" and after this call there is no way to know which rows have been changed and no simple way to update your database. So remove that line

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

At this point you are ready to commit your changes to the database. You can use the SqlCommandBuilder object to create the sql commands required to update your rows. But this will work only if you have retrieved the primary key of your database table.
So assuming that ScreenName is the primary key then you can write

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

I am making the assumption that ScreenName is the primary key for the ScreenCheckDuplicates table. Methods to Update a table use the primary key.

Keep your database objects local so you can control if they are closed and disposed. Using...End Using blocks handle this for you even if there is an error.

Always used Parameters to avoid Sql injection. I had to guess at the SqlDbType and the field size. Check your database for the actual values and adjust the code accordingly.

When you use a DataAdapter you need to provide the commands that you need. A command builder will do this for you. Don't call .AcceptChanges on the DataTable until you have used the Update method on the DataAdapter.

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

The following alternative method is a bit better because it only requires a single hit on the database.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM