OracleDataAdapter.Update cannot update database - vb.net

Using Command As OracleCommand = conn.CreateCommand()
Command.CommandText = sSql
rsLFExcelRaw = New OracleDataAdapter(Command)
cbOracleCmdBuilder = New OracleCommandBuilder(rsLFExcelRaw)
dsLFExcelRaw = New DataSet()
rsLFExcelRaw.Fill(dsLFExcelRaw, "LF_EXCEL_RAW")
End Using
As stated above, I have a oraclecommand and oracledataadapter, I can retrieve data from database.
Then I update some value and add a new rows to the dataset, and do following:
dsLFExcelRaw.Tables(0).Rows.Add(row)
dsLFExcelRaw.AcceptChanges()
rsLFExcelRaw.Update(dsLFExcelRaw, "LF_EXCEL_RAW")
However, I cannot update the databse. Any ideas?

problem solved, after dsLFExcelRaw.AcceptChanges(), no change will be made.
So I change it to:
rsLFExcelRaw.Update(dsLFExcelRaw, "LF_EXCEL_RAW")
dsLFExcelRaw.AcceptChanges()

Related

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

What would cause my dataset to drop a row?

I have a SQL statement that, when ran in SSMS, returns 6 rows. After attaching the statement to the command text of a VB.NET SQLCommand with a command type of Text, reading it with a SqlDataReader, and attaching it to a dataset, the returned dataset only has 5 rows.
At first, I assumed it was an issue with the data. However, after several bouts of removing and adding rows to the source table with varying data, it was obvious that I was always getting the total row count - 1. I then decided to just use a SQLDataAdapter to populate the DataSet and the proper number of rows was returned.
Dim ds As New DataSet
Dim sqlCmd as New SqlCommand
Dim sqlCn As New SqlConnection
Dim sqlR As New SqlCommand
sqlCn.ConnectionString = "SomeConnectionString"
With sqlCmd.CommandText = "Select * from DummyTable"
.CommandType = CommandType.Text
.Connection = sqlCn
End With
sqlCn.Open()
sqlR = sqlCmd.ExecuteReader
sqlR.Read()
If sqlR.HasRows() Then
ds.Tables.Add("DummyTable")
ds.Tables(0).Load(sqlR)
return ds
End If
From here, I'm expecting to see the 6 rows from DummyTable. Instead, I'm seeing only 5.
However, if I use the following:
Dim da as SqlDataAdapter
Using sqlCn
da.SelectCommand = New SqlCommand(sqlCmd.CommandText, sqlCn)
da.Fill(ds)
End Using
Return ds
I get the full 6 rows. Is there something I'm missing about the way a DataSet's Tables.Add(tableName) or Tables(n).Load(dataReader) works? I had never worked with SqlDataReaders prior to this and was told to stick with them as our other projects use them.
Your code is already reading the first line of the query with the line sqlR.Read(). This line is unnecessary in your code. Remove it and it will work fine.
Also SqlCommand, SqlConnection and SqlDataReader implement iDisposable, so be sure to use using-statement with them:
Using sqlCn As New SqlConnection("SomeConnectionString")
sqlCn.Open()
Using sqlCmd as New SqlCommand
With sqlCmd.CommandText = "Select * from DummyTable"
.CommandType = CommandType.Text
.Connection = sqlCn
End With
Using sqlR As SqlDataReader = sqlCmd.ExecuteReader
If sqlR.HasRows() Then
Dim ds As New DataSet
ds.Tables.Add("DummyTable")
ds.Tables(0).Load(sqlR)
return ds
End If
End Using
End Using
End Using

Write DataSet changed back to Access database

I have the following code to alter the data, now I actually want to write said data back to the TESTS_TMP table in the Access database, how do I do that? I thought the adapter update did that but it doesn't?
Dim dataSet As DataSet = New DataSet
Using connection As New OleDbConnection(FileLocations.connectionStringNewDb)
connection.Open()
Dim adapter As New OleDbDataAdapter()
adapter.SelectCommand = New OleDbCommand("SELECT * FROM TESTS_TMP;", connection)
Dim builder As OleDbCommandBuilder = New OleDbCommandBuilder(adapter)
adapter.Fill(dataSet)
'MsgBox(dataSet.Tables(0).Rows.Count)
'Code to modify the data in the DataSet here.
Dim id As Integer = 300
For i As Integer = 0 To dataSet.Tables(0).Rows.Count - 1
dataSet.Tables(0).Rows(i).Item(0) = id
id = id + 1
Next
' Without the OleDbCommandBuilder this line would fail.
'builder.GetUpdateCommand()
'adapter.Update(dataSet)
Try
adapter.Update(dataSet.Tables(0))
dataSet.AcceptChanges()
Catch x As Exception
' Error during Update, add code to locate error, reconcile
' and try to update again.
End Try
End Using
MsgBox(dataSet.Tables(0).Rows(1).Item(0))
You're calling AcceptChanges. and it is marking all of the rows as being unmodified, so they are never updated in the database. Remove this call.

Refresh DataGridView after executing SQL Command?

Here is my code:
cn.Open()
cmd.CommandText = "insert into Student values('" ......
cmd.ExecuteNonQuery()
cn.Close()
After closing the connection I want my DataGridView to refresh it's data's also.
I am new in VB.NET I tried datagridview.refresh() but it's not working as I think it's like repainting not updating it's data's.
Thanks.
If you update the underlying business object, the UI should update automatically. My guess it that you forgot to do data binding, for example DataGridView.DataSource = yourDataTable.
EDIT: the easiest way from where you are right now would probably be to replace this:
cmd.ExecuteNonQuery()
with this:
Dim dt As New DataTable
dt.Load(cmd.ExecuteReader())
and then:
DataGridView.DataSource = dt
If you need database updates, you may want to use a DataAdapter and its Update method. The overload I linked is specifically for a DataTable, i.e. you don't need a DataSet, unless you have it already.
As #Neolisk said you have to do databinding .. for example
Dim ds as DataSet
Dim sSql As New OleDb.OleDbCommand
sSql = cnEZApp.CreateCommand()
cmd = New Data.OleDb.OleDbDataAdapter("SELECT * FROM student ORDER by kode", conn)
cmd.Fill(ds, "student")
dgvGuru.DataSource = ds.Tables("student")
So, to update table as datasource you have to do
sSql.CommandText = "insert into Student(...) values(...)"
cmd.UpdateCommand = sSql
cmd.UpdateCommand.ExecuteNonQuery()
cmd.ExecuteNonQuery()

Deleting a record from dataset and sql server

I am trying to delete a record from a DataTable and then update the database that it is attached to.
I delete a row of my DataGridView and then update my Dataset using:
Me.Tab2_DGVDuty.Rows.RemoveAt(Me.Tab2_DGVDuty.CurrentRow.Index)
ds1.AcceptChanges()
Tab2_DGVDuty.Refresh()
I then call my adapter.update as below:
Dim adapter As New SqlDataAdapter
Dim cmdBuilder As New SqlCommandBuilder(adapter)
Dim DutyDetails As String = "SELECT * from MyTable"
adapter.SelectCommand = New SqlCommand(DutyDetails, SQLConn)
adapter.UpdateCommand = cmdBuilder.GetUpdateCommand
adapter.DeleteCommand = cmdBuilder.GetDeleteCommand
Dim cb As SqlCommandBuilder = New SqlCommandBuilder(adapter)
adapter.Update(ds1.Tables("DT_Table"))
But when i reload the data my record is still there. If I change a value and update this works fine but for some reason the delete doesnt.
Any help much appreciated.
EDIT:
OK I changed my delete to the following as suggested below:
ds1.Tables("DT_Table").Rows(Tab2_DGVDuty.CurrentRow.Index).Delete()
This is attached to a button, it deletes fine the first time but on the second press to delete another record nothing happens. If I use
ds1.AcceptChanges()
then it works fine. However, if i use the above then my code below does not delete anything from the database:
Dim adapter As New SqlDataAdapter
Dim cmdBuilder As New SqlCommandBuilder(adapter)
Dim DutyDetails As String = "SELECT * from MyTable"
adapter.SelectCommand = New SqlCommand(DutyDetails, SQLConn)
adapter.UpdateCommand = cmdBuilder.GetUpdateCommand
adapter.DeleteCommand = cmdBuilder.GetDeleteCommand
Dim cb As SqlCommandBuilder = New SqlCommandBuilder(adapter)
adapter.Update(ds1.Tables("DT_Table"))
You don't want to remove the DataRow from the DataTable, you want to Delete it
ds1.Tables("DT_Table").Rows(Tab2_DGVDuty.CurrentRow.Index).Delete()
Don't call ds1.AcceptChanges() afterwards since the Update will not recognize that this row has changed anymore then because it will change it's RowState to Unchanged. DataAdapter.Update calls AcceptChanges as the last step implicitely, not you.
I assume that Tab2_DGVDuty is a DataGridView and not the DataTable, i've taken that into account above.