Error: Dynamic SQL generation for the UpdateCommand is not supported against a SelectCommand that does not return any key column information
I am trying to solve the following problem- getting my application to write back to my database. The app is hitting the exception title listed above. I have been reading about database CRUD operations here- http://www.homeandlearn.co.uk/NET/nets12p7.html
I know from other reading I have done that I need to have a primary key. Can someone explain how this relates when you are using a data set and data adapter? Is this error related to my actual database or the in memory dataset?
I also realize that I have created a dataset based on one query. Do I need a different query (INSERT) when I reach a ticket not found condition?
Private Sub BtnQuery_Click(sender As Object, e As EventArgs) Handles BtnQuery.Click
sql = "SELECT [Ticket ID] AS Ticket_ID , [Foundstone] AS Foundstone, [ID] AS ID FROM [Table MAIN] WHERE ([Ticket Days OverDue] >= 0)" 'define the query
da = New OleDb.OleDbDataAdapter(sql, con)
da.Fill(ds, "MAIN")
If ds.Tables("MAIN").Rows.Count > 0 Then
TxtRows.Text = ds.Tables("MAIN").Rows.Count
maxrows = Val(TxtRows.Text.ToString)
End If
For i = 0 To maxrows - 1
If i >= 0 Then
result = ds.Tables("MAIN").Rows(i).Item("Ticket_ID")
WebBrowser1.Navigate("https://fs-enterprise.my.private.url/remediation/ticket.exp?ticket=" & result)
Do While WebBrowser1.ReadyState <> WebBrowserReadyState.Complete
Application.DoEvents()
Loop
WebBrowser1.AllowNavigation = True
'<div id="MessageGood_0" class="mvm-status-message msm-msg msm-msg-img" style="background-image:url(/images/fam/cross.png);">The specified ticket does not exist, or is not currently available.</div>
For Each el As HtmlElement In WebBrowser1.Document.GetElementsByTagName("div")
If (el.GetAttribute("id").Equals("MessageGood_0")) Then
TxtTicket.Text = ds.Tables("MAIN").Rows(i).Item("Ticket_ID")
'Try
Dim cb As New OleDb.OleDbCommandBuilder(da)
cb.QuotePrefix = "[" 'allows update if table name or field is a reserved word in MS Access
cb.QuoteSuffix = "]" 'allows update if table name or field is a reserved word in MS Access
ds.Tables("MAIN").Rows(i).Item("Foundstone") = "Not Found"
da.Update(ds, "MAIN")
da.UpdateCommand = cb.GetUpdateCommand()
MsgBox("Ticket Not Found")
'Catch ex As Exception
'MsgBox(ex.Message.ToString, , "Error")
'End Try
Else
'<input class="boldbutton" type="button" value="Verify" onclick="this.form.knob.value='ReqVerify';this.form.verify.value=1;this.form.submit()"></td>
TxtTicket.Text = ds.Tables("MAIN").Rows(i).Item("Ticket_ID")
For Each element As HtmlElement In WebBrowser1.Document.GetElementsByTagName("INPUT")
If (element.GetAttribute("value").Equals("Verify")) Then
element.InvokeMember("click")
End If
Next
End If
Next
End If
Next
MessageBox.Show("All Tickets Have Been Processed")
Me.Close()
con.Close()
End Sub
The answer to your first question is that the primary key needs to be set on the actual database table rather than the in-memory dataset.
In answer to your second question, you can update the database from your dataset using the following:
Dim cb As New OleDb.OleDbCommandBuilder(da)
ds.Tables("MAIN").Rows(i).Item("Foundstone") = "Not Found"
da.UpdateCommand = cb.GetUpdateCommand()
da.Update(ds, "MAIN")
Related
I need some help with my validation. What I'm supposed to do is check weather the number in the textbox is greater than or less than the quantity (stored in an SQL table called inventory) for that specific item (selected from the drop downlist). If the number in the textbox is greater than then quantity for that item then a message pops up saying that there isn't enough quantity for that item. If the number is less than the quantity in the SQL table for that item then it updates that quantity for that item. What my problem is, is that my validation isn't going to my second validation. It's like its stuck at the first if statement and I don't know how to fix it. I feel like its something very simple but I just can't put my finger on it. Here's my code:
Dim DA As New SqlDataAdapter("Select itemID, quantity From Inventory", con)
Dim DT As New DataTable
Try
If DT.Rows.Count > 0 Then DT.Rows.Clear()
DA.Fill(DT)
With DropDownList1
.DataSource = DT
.DataTextField = "itemID"
.DataValueField = "quantity"
.DataBind()
.Items.Insert(0, "Please Select a Customer")
End With
Catch ex As Exception
Response.Write(ex.Message)
End Try
End Sub
Protected Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim PurchaseQuantity, UP, SL As String
PurchaseQuantity = TextBox1.Text
Dim cmdUpdate As New SqlCommand("Update Inventory SET quantity = #p1 where price = #p2", con)
With cmdUpdate.Parameters
.Clear()
.AddWithValue("#p1", PurchaseQuantity)
.AddWithValue("#p2", DropDownList1.SelectedValue)
End With
Dim cmdSelect As New SqlCommand("Select quantity From Inventory where itemID = #p1", con)
With cmdSelect.Parameters
.Clear()
.AddWithValue("#p1", DropDownList1.SelectedValue)
End With
Try
If con.State = ConnectionState.Closed Then con.Open()
UP = cmdUpdate.ExecuteNonQuery
SL = cmdSelect.ExecuteScalar
Catch ex As Exception
Response.Write(ex.Message)
Finally
con.Close()
End Try
If PurchaseQuantity > SL Then
MsgBox("There is not enough quantity for this item", vbExclamation, "Error")
Else
If PurchaseQuantity < SL Then
MsgBox("Inventory is updated", vbExclamation, "Error")
UP -= PurchaseQuantity
End If
End If
So, you're seeing the error "There is not enough quantity for this item"?
I see a few problems:
Update Inventory SET quantity = #p1 where price = #p2
should be:
Update Inventory SET quantity = quantity - #p1 where itemID = #p2
Also, the order of the commands is backwards. The SELECT should happen before the UPDATE. (Otherwise, you're deducting the quantity from your inventory, THEN checking that you have enough to fill the order.)
Also, this whole operation should be transaction-bounded. You're open to a race condition, of sorts, with the current code. (If (2) simultaneous orders are placed, you could end up with a negative inventory quantity.) Or, at least, put a check constraint on the table (Inventory.quantity > 0) so it forces a SQL Exception in VB and halts the update.
I have a dialog with a combobox listing the years an event was held.
Changing the year, changes the following list boxes
One list box 'called inEvent' shows all golfers the attended said event.
The other list box called 'available' that shows every golfer we have in our database that did not attend that years event
It has two buttons. One removes golfers from 'inEvent' and moves them to 'available'. This button works.
The other button does the opposite. It adds available golfers to the selected event year. But it gives me the error -
"The statement has been terminated. Cannot insert the value NULL into column 'intGolferEventYearID', table 'dbo.TGolferEventYears'; column does not allow nulls. INSERT fails."
Changing any line of code in VB results in a different error. So I think the error has to come from SQL itself which I don't know much about. Only other thing I can think of is the listbox is giving the wrong information.
Private Sub btnAddAuto_Click(sender As Object, e As EventArgs) Handles btnAddAuto.Click
Dim strInsert As String = ""
Dim cmdInsert As OleDb.OleDbCommand ' used for our Select statement
Dim dt As DataTable = New DataTable ' table we will load from our reader
Dim intRowsAffected As Integer
' open the DB
OpenDatabaseConnectionSQLServer()
' Build the select statement
strInsert = "INSERT INTO TGolferEventYears ( intGolferID, intEventYearID) Values (" & lstAvailable.SelectedValue & ", " & cboEvents.SelectedIndex + 1 & ")"
' Retrieve all the records
cmdInsert = New OleDb.OleDbCommand(strInsert, m_conAdministrator)
intRowsAffected = cmdInsert.ExecuteNonQuery()
' close the database connection and reload the form so the changes are shown
CloseDatabaseConnection()
frmEventsGolfers_Load(sender, e)
End Sub
I separated the data access code from the user interface. This will make it easy to remove data access entirely from the Form if you later desire.
Private Sub MoveGolfer(GolfID As Integer, YearID As Integer)
'If you keep your connections local you can be sure they are
'closed and disposed which is what the Using...End Using blocks do.
Using cn As New SqlConnection("Your connection string")
Using cmd As New SqlCommand("INSERT INTO TGolferEventYears ( intGolferID, intEventYearID) Values (#Golf, #Year;")
'Always use parameters to protect against Sql injection
cmd.Parameters.Add("#Golf", SqlDbType.Int).Value = GolfID
cmd.Parameters.Add("#Year", SqlDbType.Int).Value = YearID
cn.Open()
cmd.ExecuteNonQuery()
End Using
End Using
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim GolferID As Integer = CInt(lstAvailable.SelectedValue)
Dim Year As Integer = cboEvents.SelectedIndex + 1
Try
MoveGolfer(GolferID, Year)
Catch ex As Exception
'Catch a more specific exception and handle accordingly
MessageBox.Show(ex.Message)
End Try
End Sub
Since I don't really understand SQL I didn't realize my PK didn't have the IDENTITY tag added in the table. Adding this fixed my issue.
Here is the code I added
Dim strSelect As String
Dim cmdSelect As OleDb.OleDbCommand
Dim drSourceTable As OleDb.OleDbDataReader
Dim intNextHighestRecordID As
strSelect = "SELECT MAX(intDealerAutos) + 1 AS intNextHighestRecordID " &
" FROM TDealerAutos"
'Excute command
cmdSelect = New OleDb.OleDbCommand(strSelect, m_conAdministrator)
drSourceTable = cmdSelect.ExecuteReader
'Read result( highest ID )
drSourceTable.Read()
'Null? (Empty Table)
If drSourceTable.IsDBNull(0) = True Then
'Yes, start numbering at 1
intNextHighestRecordID = 1
Else
'No, get the next highest ID
intNextHighestRecordID = CInt(drSourceTable.Item(0))
End If
'Build the select statement
strInsert = "INSERT INTO TDealerAutos ( intDealerAutos, intDealerID, intAutoID)" &
"Values (" & intNextHighestRecordID & ", " & cboDealers.SelectedValue & ", " & lstAvailable.SelectedValue & ")"
I have a VB form and a combobox linked to a datasource.
The database has two tables Position (SLOT, ID_WH) and Warehouse (ID_WH, WH_NAME).
The combobox is linked to the warehouse, and it shows the WH_NAME.
I need to get the ID_WH to insert into the Position table.
The code is:
WH_CB.DisplayMember = "Warehouse" 'Column name
WH_CB.ValueMember = "ID_WH" 'Column name2
'ADD INFO TO Position (SLOT)
Dim Remove_space_start As String = SLOT_TXT.Text
Dim CharStart() As Char = {" "}
Dim Stringstart As String = Remove_space_start.TrimStart(CharStart)
Dim CharEnd() As Char = {" "}
Dim StringEnd As String = Stringstart.TrimEnd(CharEnd)
Try
objconnection.Open()
cmd.Connection = objconnection
cmd.CommandText = "InsertDataIntoPosition"
cmd.CommandType = CommandType.StoredProcedure
cmd.Parameters.AddWithValue("SLOT", StringEnd)
cmd.Parameters.AddWithValue("ID_WH", WH_CB.SelectedValue)
cmd.ExecuteNonQuery()
MessageBox.Show("sucess")
'Refresh DATAGRID
dgv_slot.DataSource = Nothing
dgv_slot.Refresh()
Dim str As String = "select * from Position"
Using cmd As New SqlCommand(str, objconnection)
Using da As New SqlDataAdapter(cmd)
Using newtable As New DataTable
da.Fill(newtable)
dgv_slot.DataSource = newtable
End Using
End Using
End Using
Catch ex As Exception
MessageBox.Show("Error while inserting record on table..." &
ex.Message,
"Insert Records")
Finally
objconnection.Close()
End Try
I've tried to show the whcb with a messagebox, and it shows the ID_WH, but trying to insert data into the table I get the error:
System.Data.SqlClient.SqlException: 'Conversion failed when converting the nvarchar value 'Armazem4 ' to data type int.'
Any help?
It's solved, thank you very much.
I had the same field name (with different types) in different tables, So I was forcing the wrong one to get the information.
After I corrected that, its working fine.
I have a filter so it filters the binding source by the customerID. But what if the customer id doesnt exist? When i enter id = 3 and doesnt exist it messes up my whole binding per say, meaning it nulls everything and when i want to reopen the binding it crashes saying it cant locate the item. So trying not to go into detail with the errors, i want to make it so if it results back to null then present the user with an error saying not located etc and enter again, if correct/present then do its filter job.
My code:
dim filterstring as string
filterstring = CStr(bsorder.Filter = "id = " & custid & "")
If filterstring.Count() = 0 Then
MessageBox.Show("Error! try again!", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
Else
bsorder.Filter = "ID = " & custid & ""
End If
I needed to check if the row existed before applying the filter, to do so i used a Try/Catch method to successfully know rather the id existed or not. The code that worked is below:
Try
Using myConnection As OleDbConnection = New OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=.\yous.accdb")
myConnection.Open()
Dim str As String
str = "SELECT * FROM table WHERE whateverID=#ID "
Using cmd As OleDbCommand = New OleDbCommand(str, myConnection)
cmd.Parameters.AddWithValue("#ID", custid)
Using dr As OleDbDataReader = cmd.ExecuteReader
If dr.HasRows Then
dr.Read()
End Using
End Using
End Using
Catch ex As Exception
MsgBox(ex.ToString)
End Try
I am making a vb .net winform project that uses a sql server database. A user inputs the details of a person (firstName, lastName, company, contactNumber, etc.) visiting a factory into textboxes, hits the save details button, and this saves the data in the datatable. This works fine, the problem is the next part. The user is then redirected to another form where the input details are shown from the database. This works for the first record but not for any record input after that, I get an error that says "There is no row at position 'n'" and the following line of code is highlighted in the form_Load:
txtFirstName.Text = CStr(dtVisitorDetails.Rows(CInt(CDbl(txtIdNumber.Text) - 1)).Item(1))
It is telling me that any rows after row 0 are not there but I know they are because I have input them and they are showing up in the datatable in the sql server database manager.
I cannot sort this problem, any help with this would be greatly appreciated. I am attaching the rest of the code that's involved with this problem.
Thanks in advanced.
Private Sub previousVisitor_Load(sender As Object, e As EventArgs) Handles MyBase.Load
connectionString = "Data Source=.\SQLExpress;InitialCatalog=Visitors;" & _
"IntegratedSecurity=True;MultipleActiveResultSets=True"
sqlVisitorDetails = "SELECT * FROM visitorDetails WHERE idNumber=#idNumber"
sqlCon.Open()
sqlCmd = New SqlCommand(sqlVisitorDetails, sqlCon)
sqlCmd.Parameters.AddWithValue("#idNumber", txtIdNumber.Text)
dtVisitorDetails = loadDtVisitorDetails()
txtFirstName.Text = CStr(dtVisitorDetails.Rows(CInt(CDbl(txtIdNumber.Text) - 1)).Item(1))
txtLastName.Text = CStr(dtVisitorDetails.Rows(CInt(CDbl(txtIdNumber.Text) - 1)).Item(2))
txtCompany.Text = CStr(dtVisitorDetails.Rows(CInt(CDbl(txtIdNumber.Text) - 1)).Item(3))
txtContactNumber.Text = CStr(dtVisitorDetails.Rows(CInt(CDbl(txtIdNumber.Text) - 1)).Item(4))
txtCountryCode.Text = CStr(dtVisitorDetails.Rows(CInt(CDbl(txtIdNumber.Text) - 1)).Item(5))
txtEmail.Text = CStr(dtVisitorDetails.Rows(CInt(CDbl(txtIdNumber.Text) - 1)).Item(7))
sqlCmd.Dispose()
sqlCon.Close()
End Sub
Private Function loadDtVisitorDetails() As DataTable
Dim dtVisitorDetails As DataTable = Nothing
sqlVisitorDetails = "SELECT * FROM visitorDetails WHERE idNumber=" & txtIdNumber.Text
dtVisitorDetails = fillDtVisitorDetails(sqlVisitorDetails)
Return dtVisitorDetails
End Function
Public Function fillDtVisitorDetails(ByVal sqlVisitorDetails As String) As DataTable
Dim dtVisitorDetails As New DataTable
Dim da As New SqlDataAdapter
Dim conCmd As New SqlCommand
conCmd.CommandText = sqlVisitorDetails
da.SelectCommand = conCmd
da.SelectCommand.Connection = sqlCon
dtVisitorDetails.Columns.GetEnumerator()
da.Fill(dtVisitorDetails)
Return dtVisitorDetails
End Function
Since you can only have 1 row for each unique ID number, when you search and filter as WHERE idNumber = ID Number in form, you should get at most 1 record. That means the DataTable can have at most 1 row.
When you access the Rows of a DataTable like dt.Rows(ID), you are trying to access the row at position number ID in the collection of rows. Therefore, when you do dtVisitorDetails.Rows(CInt(CDbl(txtIdNumber.Text) - 1) for any value of ID number greater than 1, it will fail because that index simply does not exist in the table.
Instead, you should directly use dtVisitorDetails.Rows(0) to access the row. Since you have filtered by the ID Numberm you will only get the details for that person by doing so. Finally, remember to add a check for the row count in the table, so that if you search for an ID which has no records, there will not be an error in trying to retrieve from the table.
Pseudo-code:
If dtVisitorDetails.Rows.Count > 0
txtFirstName.Text = CStr(dtVisitorDetails.Rows(0).Item(1))
...
End If