Visual basic (.net) Insert new record question - vb.net

i am a novice, trying to add a new record to a php myadmin database, the secondDB requires an "Id" to be inserted with the data.
the rest of the project uses data bound fileds.
so i generate the new record with
FirstDB.addnew()
secondDB.addnew()
then try to run the below
Call Connection() 'this gets My.Settings.companyConnectionString and opens the connection
Dim str As String = ("SELECT max(Id) FROM FirstDB")
cmd = New MySqlCommand(str, conn)
cmd.CommandType = CommandType.Text
Dim result As Integer = cmd.ExecuteScalar +1 'this will get the number and increase by one
Using cmd As New MySqlCommand()
With cmd
.CommandText = "insert into SecondDB(`id`) values (#id)"
.Parameters.AddWithValue("#id", result)
End With
End Using
conn.Dispose()
also tryed
DataSet.Secondtable.Id.DefaulValue = result
SecondDBbindingSource.Current.item("Id") = result
the secondBD refuses to save without the missing "ID".
if you put the resut in a data bound box it works out fine, but i dont want to have text boxes scatterd around.
can anyone give me some guideance ?

FirstDB.addnew()
secondDB.addnew()
I have no idea what this code is doing.
Call Connection()
Don't do this. Connections need to be declared and disposed in the method where they are used. Using blocks take care of this for us even it there is an error.
Dim str As String = ("SELECT max(Id) FROM FirstDB")
This is not a good way to find the Id you are looking for. In MySql you can add SELECT LAST_INSERT_ID(); to the Insert for FirstDB (terrible name for a table). In a multi-user environment Max will fail.
cmd.CommandType = CommandType.Text
The default type for a command is the Text type so you don't have to explicitly set this property. Interesting that you don't set this property when you create a new command a few lines down.
Dim result As Integer = cmd.ExecuteScalar + 1
ExecuteScalar returns an Object. You cannot add one to an Object. Why do you want to increment this value? The foreign key in secondDB should match the primary key in FirstDB. You said in comments both tables have a primary key field that is auto increment.
.CommandText = "insert into SecondDB(`id`) values (#id)"
Is that all you are entering into the new record? Not a very informative record.
conn.Dispose()
What if an error occurred. Your connection would never be closed or disposed.
DataSet.Secondtable.Id.DefaulValue = result
SecondDBbindingSource.Current.item("Id") = result
I have no idea what you are doing here.
I have to make up a table structure for the 2 tables (not DB, tables).
Private Sub OPCode(Company As String, Contact As String, Address As String)
Dim IdFromFirstDB As Integer
Dim sql = "Insert Into FirstDB (CompanyName, ContactName) Values (#Name, #Contact) Select LAST_INSERT_ID();"
Using cn As New MySqlConnection(My.Settings.companyConnectionString)
Using cmd As New MySqlCommand(sql, cn)
cmd.Parameters.Add("#Name", MySqlDbType.VarChar, 200).Value = Company
cmd.Parameters.Add("#Contact", MySqlDbType.VarChar, 100).Value = Contact
cn.Open()
IdFromFirstDB = CInt(cmd.ExecuteScalar)
End Using
sql = "Insert Into secondDb (Address, CompanyID) Values (#Address, #ID);"
Using cmd As New MySqlCommand(sql, cn)
cmd.Parameters.Add("#Address", MySqlDbType.VarChar, 200).Value = Address
cmd.Parameters.Add("#ID", MySqlDbType.Int32).Value = IdFromFirstDB
cmd.ExecuteNonQuery()
End Using
End Using
End Sub

Related

Hi folks. I am trying to update an app to VB dot net from vb6 and have enouctered a really basic problem. I will add the code of course in a sec. I

Trying to update an old VB6 app to VB.Net. I am having trouble with syntax, I think. In any case it is a simple matter of inserting a new record to the autolog table. (code below).
I would like to ask something else that is often not documented too. It seems that I have to use command builders and so on - is there no way I can simply use an SQL statement and execute it against the background table? The tables are in Access while I am developing but will be scaled up on the final release of the software.
I have altered my code to the following by making use of the error suggestions at the foot of mygui.
It now looks like this and the only thing is that it is throwing a logic error at me which is that every end function must have a preceding "function". Perhaps I am being a little bit dim
Function MAutolog(ByVal Action As String) As Boolean
Dim SQL = "Insert Into Autolog (Action) Values (#Action)"
Using con As New OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\Users\PC User\Documents\Freightmaster\resources\freightmaster.accdb"),
cmd As New OleDb.OleDbCommand(SQL, con)
cmd.Parameters.Add("#Action", OleDb.OleDbType.VarChar).Value = Action
con.Open()
cmd.ExecuteNonQuery()
End Using
MAutolog = True
End Function
I would like to thank you for your help in advance. I can not tell you how much I will appreciate it.
Code
Module ModFunctions
Function MAutolog(ByVal UserID As Long, ByVal Action As String) As Boolean
Dim dbprovider As String
Dim dbsource As String
Dim mydocumentsfolder As String
Dim fulldatabasepath As String
Dim TheDatabase As String
Dim SQL As String
Dim DS As New DataSet
Dim da As OleDb.OleDbDataAdapter
Dim con As New OleDb.OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\Users\PC User\Documents\Freightmaster\resources\freightmaster.accdb")
con.Open()
'----------------------------
SQL = "Select * from Autolog"
da = New OleDb.OleDbDataAdapter(SQL, con)
da.Fill(DS, "Log")
con.Close()
Dim CB As New OleDb.OleDbCommandBuilder(da)
Dim DSNEWROW As DataRow
DSNEWROW = DS.Tables("Log").NewRow()
DSNEWROW.Item("UserID") = UserID
DSNEWROW.Item("Action") = Action
DS.Tables("log").Rows.Add(DSNEWROW)
da.Update(DS, "log")
MAutolog = True
End function
Database objects like Connection and Command use unmanaged code and need their Dispose methods to release these resources. Either call this method on these objects or use Using...End Using blocks which will do this for you even if there is an error. In this code, both the Connection and Command are included in the Using block by separating them be a comma.
By Val is the default so is not necessary.
Always use parameters to avoid sql injection. Using values directly from user input can allow malicious code to be executed on your database. The value of a parameter is not considered as executable code by the database.
OleDb does not care about parameter names. You could just as easily use ? in the sql statement. I use names for readability. You do need some sort of name to add the parameter. OleDb considers the position of the parameter in the sql statement. The position must match the order that the parameters are added to the parameters collection.
This is the code for the Insert if UserID in an auto-number field. You do not provide a value for auto-number fields. The database will handle that.
Function MAutolog(Action As String) As Boolean
Dim SQL = "Insert Into Autolog (Action) Values (#Action)"
Using con As New OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\Users\PC User\Documents\Freightmaster\resources\freightmaster.accdb"),
cmd As New OleDbCommand(SQL, con)
cmd.Parameters.Add("#Action", OleDbType.VarChar).Value = Action
con.Open()
cmd.ExecuteNonQuery()
End Using
MAutolog = True
End Function
If UserID is not auto-number
Function MAutolog(UserID As Long, Action As String) As Boolean
Dim SQL = "Insert Into Autolog (UserID, Action) Values (#UserID, #Action)"
Using con As New OleDb.OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\Users\PC User\Documents\Freightmaster\resources\freightmaster.accdb"),
cmd As New OleDbCommand(SQL, con)
cmd.Parameters.Add("#UserID", OleDbType.Integer).Value = UserID
cmd.Parameters.Add("#Action", OleDbType.VarChar).Value = Action
con.Open()
cmd.ExecuteNonQuery()
End Using
MAutolog = True
End Function

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

Populating an Auto-Incremented ID created through VB.net from a Parent table to multiple child tables in SQLite

New to VB.net and have been trying to get this to work for a while. As the code stands right now, I'm only able to update each table separately which makes sense but I need help getting an ID from a newly created record to the child tables in my DB. My tables are already set up with PKs and FKs and my connection string has ...foreign keys=true; in it.
Here is what I have so far:
...Dim cmd As New SQLiteCommand
cmd.Connection = myconnection
cmd.CommandText = "Insert into dbo_DataLog (ProductionDate,ProductionOrder,StyleID) values (#ProductionDate,#ProductionOrder,#StyleID)"
cmd.Parameters.AddWithValue("#ProductionDate", dtpDate.Text)
cmd.Parameters.AddWithValue("#ProductionOrder", txtProdOrder.Text)
cmd.Parameters.AddWithValue("#StyleID", StyleID)
cmd.ExecuteNonQuery()
cmd.Parameters.Clear()
Dim cmd2 As New SQLiteCommand
cmd2.Connection = myconnection
cmd2.CommandText = "Insert into dbo_WeightAndWidth (LabTech_ID,PunchWeight,OverallWidth,UsableWidth,GSM) values (#LabTech_ID,#PunchWeight,#OverallWidth,#UsableWidth,#GSM)"
cmd2.Parameters.AddWithValue("#LabTech_ID", "5")
cmd2.Parameters.AddWithValue("#PunchWeight", txtPW.Text)
cmd2.Parameters.AddWithValue("#OverallWidth", txtOW.Text)
cmd2.Parameters.AddWithValue("#UsableWidth", txtUW.Text)
cmd2.Parameters.AddWithValue("#GSM", txtGSM.Text)
cmd2.ExecuteNonQuery()
cmd2.Parameters.Clear()
myconnection.Close()...
I have done a lot of searching and can't seem to get anything to work; I know it's a pretty crappy query as is since it's just a repeat of the original.
Please assist if you're able to do so!
Edit:
Changed up my code to consolidate it and used Dim dataID As String = "Select seq from sqlite_sequence where name='dbo_DataLog'"and executed that to get utilize the temp table the SQLite uses.
Dim cmd As New SQLiteCommand
cmd.Connection = myconnection
'look up dataID that was just executed
Dim dataID As String = "Select seq from sqlite_sequence where name='dbo_DataLog'"
Dim mycmd As New SQLiteCommand(dataID, myconnection)
Dim value As Object = mycmd.ExecuteScalar()
cmd.CommandText = "Insert into dbo_DataLog (ProductionDate,ProductionOrder,StyleID) values (#ProductionDate,#ProductionOrder,#StyleID);Insert into dbo_WeightAndWidth (Data_ID,LabTech_ID,PunchWeight,OverallWidth,UsableWidth,GSM) values (#Data_ID,#LabTech_ID,#PunchWeight,#OverallWidth,#UsableWidth,#GSM) "
cmd.Parameters.AddWithValue("#ProductionDate", dtpDate.Text)
cmd.Parameters.AddWithValue("#ProductionOrder", txtProdOrder.Text)
cmd.Parameters.AddWithValue("#StyleID", StyleID)
cmd.Parameters.AddWithValue("#Data_ID", value + 1)
cmd.Parameters.AddWithValue("#LabTech_ID", "5")
cmd.Parameters.AddWithValue("#PunchWeight", txtPW.Text)
cmd.Parameters.AddWithValue("#OverallWidth", txtOW.Text)
cmd.Parameters.AddWithValue("#UsableWidth", txtUW.Text)
cmd.Parameters.AddWithValue("#GSM", txtGSM.Text)
cmd.ExecuteNonQuery()
cmd.Parameters.Clear()
myconnection.Close()

Self learning on vb.net

Currently I'm trying to understand and learn new code commands for vb.net. i have came across three codes while researching which is
"SELECT staff_id,pass_word FROM userlogin WHERE staff_id = #staff_id AND pass_word = #pass_word")
Second code:
Dim uName As New OleDbParameter("#staff_id", SqlDbType.VarChar)
Third and last:
uName.Value = txtstaffid.Text
myCommand.Parameters.Add(uName)
What are the uses of #pass_word code when you have already typed the pass_word column, Oledbparameter, and Parameters.Add?
The following code shows a bit more complete picture of what the code is doing. The Using...End Using blocks ensure that your objects are closed and disposed even if there are errors. Of course, in a real application, passwords would never be stored as plain text (too easy to hack). They would be salted and hashed but that is for another day.
Private Sub CheckPassword()
'This line assigns a Transact SQL command to a string variable.
'It will return a record with 2 columns. The #staff_id and #pass_word are parameter placeholders.
'The use of parameters limits the possibilit of SQL injection with malicious input be the user
'typing in the text box.
Dim strSQL = "SELECT staff_id,pass_word FROM userlogin WHERE staff_id = #staff_id AND pass_word = #pass_word;"
Using cn As New SqlConnection("Your connection string")
'Pass the command string and the connection to the constructor of the command.
Using cmd As New SqlCommand(strSQL, cn)
'It is unneccessary to create a command variable.
'The .Add method of the commands Parameters collection will create a parameter.
cmd.Parameters.Add("#staff_id", SqlDbType.VarChar).Value = txtstaffid.Text
cmd.Parameters.Add("#pass_word", SqlDbType.VarChar).Value = txtPassword.Text
cn.Open()
Using dr As SqlDataReader = cmd.ExecuteReader
'All we really need to know is whether we returned a row.
If dr.HasRows Then
MessageBox.Show("Login Successful")
Else
MessageBox.Show("Login Failed")
End If
End Using
End Using
End Using
End Sub

Use SQL Query in VB.net to retireve adjacant row data

I am currently coding in VB.net using windows form applications and an sql server for my tables. I am creating an order form with two comboboxes, one for the type of material to be ordered and one for a name. There is also a submit button at the bottom to run the SQL "Insert Into" code. The material combobox is filled with a column of material types from an SQL table called "tbl.channel". Each material type under that column has a part number, ID, and bundle size associated with that row. I want ALL of the information associated with that material type to write into a new table that records all the orders, with the user only selecting the material type from a combobox. How can I use a "Select From" sql code to pull the associated information with that material type to be written into a new table that tracks all the material ordered?
Try
Dim connectionstring As String = Nothing
Dim connection As SqlConnection
Dim command As SqlCommand
Dim adapter As New SqlDataAdapter
Dim ds As New DataTable
Dim i As Integer = 0
Dim sql As String = Nothing
connectionstring = "DATA SOURCE = BNSigma\Core ; integrated security = true"
sql = "Select Channel, [Bundle Size], ID from Production.dbo.tblchannel"
connection = New SqlConnection(connstring)
connection.Open()
command = New SqlCommand(sql, connection)
adapter.SelectCommand = command
adapter.Fill(ds)
Catch ex As Exception
MsgBox(ex.ToString)
End Try
Try
Using conn1 As New SqlConnection(connstring)
conn1.Open()
Using comm1 As SqlCommand = New SqlCommand("INSERT INTO Production.dbo.tbl (Channel, OrderedBy, Date1, BundleSize, ID) Values (#Channel, #Orderedby, #getdate(), #BundleSize, #ID)", conn1)
With comm1.Parameters
.AddWithValue("#Channel", CBChannel.SelectedValue)
.AddWithValue("#OrderedBy", CBName.SelectedValue)
.AddWithValue("#BundleSize", CBChannel.SelectedValue)
.AddWithValue("#ID", CBChannel.SelectedValue)
End With
End Using
End Using
Catch ex As Exception
MsgBox("Unable to make SQL connection")
MsgBox(ex.ToString)
End Try
I'm not certain I understand your goal, but are you looking to just do this?
INSERT Production.dbo.tbl (Channel, OrderedBy, Date1, BundleSize, ID)
SELECT Channel, #Orderedby, getdate(), BundleSize, ID
FROM tbl.channel
WHERE ID = #ID
I am pretty well convinced though that you should only be writing the channel.ID to the orders table -- do you have a compelling reason to write the extra values?
SQL lets you use a SELECT query to populate the values for an INSERT statement. Something like this:
Public Sub PopulateOrder(ByVal MaterialID As Integer, ByVal SalesName As String)
Dim sql As String = "INSERT INTO Production.dbo.tbl (Channel, OrderedBy, Date1, BundleSize, ID) SELECT Channel, #SalesName, current_timestamp, [Bundle Size], ID from Production.dbo.tblchannel WHERE ID = #MaterialID"
Using cn As New SqlConnection("connection string here"), _
cmd As New SqlCommand(sql, cn)
'Better to declare a specific database type than let .AddWithValue() try to infer one for you
cmd.Parameters.Add("#SalesName", SqlDbType.NVarChar, 50).Value = SalesName
cmd.Parameters.Add("#MaterialID", SqlDbtype.Int).Value = MaterialID
cn.Open()
cmd.ExecuteNonQuery()
End Using
End Sub
Call it like with code similar to this:
PopulateOrder(CBChannel.SelectedValue, CBName.SelectedValue)
But for what it's worth, it's almost always a bad idea to duplicate this information across tables.