Insert data from VB net into Postgresql - vb.net

I'm trying to input data from my vb into PostgreSQL
the source is another database on Ms Access
im using this code for connection
Public Function LoadAcces_tblpibconr() As DataTable 'ganti ini sesuai nama table
Dim Table As DataTable = New DataTable()
Command.Connection = conn.OpenConnection()
Command.CommandText = "select * from tblpibconr"
Command.CommandType = CommandType.Text
ReadRows = Command.ExecuteReader()
Table.Load(ReadRows)
ReadRows.Close()
conn.CloseConexion()
Return Table
End Function
'=====================================TABLE POSTGRESQL========================='
Public Function LoadNpgsql_tblpibconr() As DataTable
Dim Table As DataTable = New DataTable()
Cmd.Connection = connNpgsql.OpenConnection()
Cmd.CommandText = "select * from tblpibconr"
Cmd.CommandType = CommandType.Text
ReadRows1 = Cmd.ExecuteReader()
Table.Load(ReadRows1)
ReadRows1.Close()
connNpgsql.CloseConexion()
Return Table
End Function
I'm using this function for filtering the data
I'll compare the data first and take the data without a match and stored it into postgresql
Public Function CekData_tblpibconr(ByVal car As String, ByVal reskd As String, ByVal contno As String) As Boolean
Dim Table As DataTable = New DataTable()
Cmd.Connection = connNpgsql.OpenConnection()
If Cmd.Parameters.Count > 0 Then
Cmd.Parameters.Clear()
End If
Cmd.Parameters.AddWithValue("#car", car)
Cmd.Parameters.AddWithValue("#reskd", reskd)
Cmd.Parameters.AddWithValue("#contno", contno)
Cmd.CommandText = <sql>select * from tblpibconr where car=#car and reskd=#reskd and contno=#contno</sql>.Value
Cmd.CommandType = CommandType.Text
ReadRows1 = Cmd.ExecuteReader() 'ERROR System.InvalidOperationException: 'Parameter '#car' must have its value set'
Table.Load(ReadRows1)
ReadRows1.Close()
If Table.Rows.Count > 0 Then
Return False
Else
Return True
End If
Cmd.Parameters.Clear()
connNpgsql.CloseConexion()
End Function
Sub bandingkan_data_tblpibconr()
For i = 0 To DGV1.Rows.Count - 1
Dim validasi = query.CekData_tblpibconr(DGV1.Rows(i).Cells(0).Value, DGV1.Rows(i).Cells(1).Value, DGV1.Rows(i).Cells(2).Value) 'cek data dari access ke postgresql
If validasi = True Then 'jika data di access tidaj ada
'inser data
Dim a As String
If IsDBNull(DGV1.Rows(i).Cells(4).Value.ToString()) Then
a = "0"
Else
a = DGV1.Rows(i).Cells(4).Value.ToString()
End If
DGV1.Rows(i).DefaultCellStyle.BackColor = Color.MistyRose
Dim Insertdata = query.insertNpgsql_tblpibconr(DGV1.Rows(i).Cells(0).Value.ToString(), DGV1.Rows(i).Cells(1).Value.ToString(), DGV1.Rows(i).Cells(2).Value.ToString() _
, DGV1.Rows(i).Cells(3).Value.ToString(), a)
If Insertdata = True Then
' MsgBox("Masuk")
Else
MsgBox("Data Gagal DIMASUKAN")
End If
End If
Next i
LoadNpgsql_tblpibconr()
MsgBox("Selesai")
End Sub
Public Function insertNpgsql_tblpibconr(ByVal car As String, ByVal reskd As String, ByVal contno As String, ByVal contukur As String, ByVal conttipe As String) As Boolean
Cmd.Connection = connNpgsql.OpenConnection()
If Cmd.Parameters.Count = 0 Then
Cmd.Parameters.Clear()
End If
Try
Cmd.CommandText = "insert into tblpibconr(car,reskd,contno,contukur,conttipe) values(#car,#reskd,#contno,#contukur,#conttipe)"
Cmd.CommandType = CommandType.Text
Cmd.Parameters.AddWithValue("#car", car)
Cmd.Parameters.AddWithValue("#reskd", reskd)
Cmd.Parameters.AddWithValue("#contno", contno)
Cmd.Parameters.AddWithValue("#contukur", contukur)
Cmd.Parameters.AddWithValue("#conttipe", conttipe)
Cmd.ExecuteNonQuery()
str = "insert into tblpibconr(car,reskd,contno,contukur,conttipe) values(#car , #reskd , #contno, #contukur, #conttipe)"
Return True
Catch ex As Exception
MsgBox(ex.Message)
Return False
End Try
connNpgsql.CloseConexion()
End Function
this is the error that I get
System.InvalidOperationException: 'Parameter '#car' must have its
value set'
ITS Refer to ReadRows1 = Cmd.ExecuteReader() on function cekdata_tblpibconr and Dim validasi = query.CekData_tblpibconr(DGV1.Rows(i).Cells(0).Value, DGV1.Rows(i).Cells(1).Value, DGV1.Rows(i).Cells(2).Value) on sub bandingkan_data_tblpibconr
but this error appear after the data successfully inserted to my Postgresql

Before running the Function where the error occurred, I have checked if we really have a value for car.
This method demonstrates what I mean by keeping your database objects local. The connection and command are created locally in a Using block. They will be closed and disposed even it there is an error.
You can pass the connection string directly to the constructor of the connection. Likewise, pass the command text and the connection to the constructor of the command. The default CommandType is CommandType.Text so it is not necessary to explicitly set that property.
Open the connection at the last possible moment directly before the command is executed.
Public Function CekData_tblpibconr(ByVal car As String, ByVal reskd As String, ByVal contno As String) As Boolean
If String.IsNullOrEmpty(car) Then
MessageBox.Show("Car has no value")
Return True '??
End If
Dim Table As DataTable = New DataTable()
Using cn As New NpgsqlConnection(ConStr),
cmd As New NpgsqlCommand("select * from tblpibconr where car=#car and reskd=#reskd and contno=#contno;", cn)
cmd.Parameters.Add("#car", NpgsqlDbType.Varchar).Value = car
cmd.Parameters.Add("#reskd", NpgsqlDbType.Varchar).Value = reskd
cmd.Parameters.Add("#contno", NpgsqlDbType.Varchar).Value = contno
cn.Open()
Table.Load(cmd.ExecuteReader)
End Using
If Table.Rows.Count > 0 Then
Return False
Else
Return True
End If
End Function

Related

Data not showing up in DataGridView after a search query

Hello i am trying to search for data from a table using a funcion, however when i Input the number of the customerID it doesnt show up in the data gridview but the data is still passed to my textboxes. Could anyone help me in explaining what I did wrong?
Private Function SearchData(Fname As String, ID As Int32) As DataTable
Dim dt As New DataTable
Dim newds As New DataSet
Dim ssql As String = "SELECT * FROM customers WHERE fname LIKE #Fname OR CustomerID =#ID"
Using con As New SQLiteConnection(ConStr),
cmd As New SQLiteCommand(ssql, con)
con.Open()
cmd.Parameters.Add("#Fname", DbType.String).Value = Fname
cmd.Parameters.Add("#ID", DbType.Int32).Value = ID
dt.Load(cmd.ExecuteReader)
Dim da As New SQLiteDataAdapter(cmd)
da.Fill(newds, "customers")
dt = newds.Tables(0)
If dt.Rows.Count > 0 Then
ToTextbox(dt)
End If
dgvCustomerInfo.DataSource = dt
con.Close()
End Using
Return dt
End Function
Private Sub IbtnSearch_Click(sender As Object, e As EventArgs) Handles ibtnSearch.Click
If txtSearchName.Text <> "" Then
SearchData(txtSearchName.Text, "0")
Dim dt = GetSearchResults(txtSearchName.Text)
dgvCustomerInfo.DataSource = dt
ElseIf txtSearchID.Text <> "" Then
SearchData("0", txtSearchID.Text)
Dim dt = GetSearchResults(txtSearchID.Text)
dgvCustomerInfo.DataSource = dt
End If
End Sub
Try to think about what each line of code is doing. See in line comments
Private Function SearchData(Fname As String, ID As Int32) As DataTable
Dim dt As New DataTable
'Delete this line - there is no need for a Dataset
Dim newds As New DataSet
Dim ssql As String = "SELECT * FROM customers WHERE fname LIKE #Fname OR CustomerID =#ID"
Using con As New SQLiteConnection(ConStr),
cmd As New SQLiteCommand(ssql, con)
con.Open() 'Move this line - don't open the connection until directly before the .Execute...
'The Like operator would expect a pattern to match
'The interpolated string with the percent signs add wildcard characters
cmd.Parameters.Add("#Fname", DbType.String).Value = $"%{Fname}%"
cmd.Parameters.Add("#ID", DbType.Int32).Value = ID
dt.Load(cmd.ExecuteReader)
'Delete - We don't need a DataAdapter
Dim da As New SQLiteDataAdapter(cmd)
'Delete - We already have a filled DataTable
da.Fill(newds, "customers")
'Delete - same as above
dt = newds.Tables(0)
'Delete - Have no idea what this does. You are already going to display your data in a grid
If dt.Rows.Count > 0 Then
ToTextbox(dt)
End If
'Delete - You will set the DataSource in the User Interface code
dgvCustomerInfo.DataSource = dt
'Delete - End Using closes the connection and disposes the connection and command.
con.Close()
End Using
Return dt
End Function
The corrected code will look like this.
Private Function SearchData(Fname As String, ID As Int32) As DataTable
Dim dt As New DataTable
Dim ssql As String = "SELECT * FROM customers WHERE fname LIKE #Fname OR CustomerID =#ID"
Using con As New SQLiteConnection(ConStr),
cmd As New SQLiteCommand(ssql, con)
con.Open()
cmd.Parameters.Add("#Fname", DbType.String).Value = $"%{Fname}%"
cmd.Parameters.Add("#ID", DbType.Int32).Value = ID
dt.Load(cmd.ExecuteReader)
End Using
Return dt
End Function
In the user interface code I have added in line comments.
Private Sub IbtnSearch_Click(sender As Object, e As EventArgs) Handles ibtnSearch.Click
'Declare the DataTable outside the If block
'We do not need a New DataTable because SearchData is returning a DataTable
Dim dt As DataTable
If txtSearchName.Text <> "" Then
'Call only one function to return the DataTable
'SearchData is expecting 2 parameters, a String and an Integer
'Putting 0 in quotes makes it a String
dt = SearchData(txtSearchName.Text, 0)
'I removed the DataSource, Don't repeat yourself
'Assign it once after the If
ElseIf txtSearchID.Text <> "" Then
'The second argument must be an Integer, therefore the CInt()
dt = SearchData("", CInt(txtSearchID.Text))
Else
'Needed to add an Else to assign a value to dt if all else fails
dt = Nothing
End If
dgvCustomerInfo.DataSource = dt
End Sub

Database insert only works with integers, not strings

I'm attempting to insert into my database but this code only works when the variables are integers, any reason for this? Could using parameters fix this?
Public Class Floshcods
Private CardCodes As Integer
Private KeyWord As String
Private Definition As String
Public Sub New(ByVal CC As Integer)
CardCodes = CC
KeyWord = InputBox("Enter keyword")
Definition = InputBox("Enter definiton")
End Sub
Public Function GetCardCodes() As Integer
Return CardCodes
End Function
Public Function GetKeyWord() As String
Return KeyWord
End Function
Public Function GetDefinition() As String
Return Definition
End Function
End Class
================================================================
sub new()
Dim numb
Dim cn = ConnectDB()
Dim cmd As New MySqlCommand
Dim sql = "SELECT * FROM " & Tabelname & " ORDER by CardCode desc limit 1"
cmd.Connection = cn
cmd.CommandText = sql
cn.Open()
Dim result As MySqlDataReader = cmd.ExecuteReader
result.Read()
Try
numb = result.GetString(0)
Catch ex As Exception
MessageBox.Show("The selected table has no previous cards")
numb = 0
End Try
cn.Close()
Dim cardcode As Integer = numb + 1
Dim p As New Floshcods(cardcode)
Me.Controls("words" & 0).Text = p.GetKeyWord
Me.Controls("words" & 1).Text = p.GetDefinition
sql = "insert into " & Tabelname & " (CardCode,Keyword,Definition) VALUES (" & cardcode & ", " & p.GetKeyWord & ", " & p.GetDefinition & ");"
cmd.CommandText = sql
Try
cn.Open()
cmd.ExecuteNonQuery()
cn.Close()
Catch ex As Exception
MessageBox.Show("failed to add card")
End Try
end
If you need more of my code to understand, please ask.
The error I get is MySql.Data.MySqlClient.MySqlException: 'Unknown column 'test' in 'field list'.
Yes, the problem would be solved if you used SQL parameters for the values in the SQL query.
There are a few other changes that you might like to make to your code too:
It is usual to use properties rather than functions for values in a class.
Avoid Try..Catch where possible, e.g. if you can check for a value instead of having an error thrown, do so.
Some classes in .NET need to have .Dispose() called on their instances to tell it to clean up "unmanaged resources". That can be done automatically with the Using statement.
Option Strict On is useful to make sure that variable types are correct. You will also want Option Explict On. Option Infer On saves some keystrokes for when variable declarations have types obvious to the compiler.
So I suggest that you use:
Public Class Floshcods
Public Property CardCode As Integer
Public Property Keyword As String
Public Property Definition As String
Public Sub New(ByVal cardCode As Integer)
Me.CardCode = cardCode
Me.Keyword = InputBox("Enter keyword")
Me.Definition = InputBox("Enter definiton")
End Sub
End Class
and
Dim latestCardCode As Integer = 0
Dim sql = "SELECT CardCode FROM `" & Tabelname & "` ORDER BY CardCode DESC LIMIT 1;"
Using cn As New MySqlConnection("your connection string"),
cmd As New MySqlCommand(sql, cn)
cn.Open()
Dim rdr = cmd.ExecuteReader()
If rdr.HasRows Then
latestCardCode = rdr.GetInt32(0)
Else
MessageBox.Show("The selected table has no previous cards.")
End If
End Using
Dim cardcode = latestCardCode + 1
Dim p As New Floshcods(cardcode)
Me.Controls("words0").Text = p.Keyword
Me.Controls("words1").Text = p.Definition
sql = "INSERT INTO `" & Tabelname & "` (CardCode,Keyword,Definition) VALUES (#CardCode, #Keyword, #Definition);"
Using cn As New MySqlConnection("your connection string"),
cmd As New MySqlCommand(sql, cn)
cmd.Parameters.Add(New MySqlParameter With {.ParameterName = "#CardCode", .MySqlDbType = MySqlDbType.Int32, .Value = cardcode})
cmd.Parameters.Add(New MySqlParameter With {.ParameterName = "#Keyword", .MySqlDbType = MySqlDbType.VarChar, .Size = 64, .Value = p.Keyword})
cmd.Parameters.Add(New MySqlParameter With {.ParameterName = "#Definition", .MySqlDbType = MySqlDbType.VarChar, .Size = 99, .Value = p.Definition})
cn.Open()
Dim nRowsAdded As Integer = cmd.ExecuteNonQuery()
cn.Close()
If nRowsAdded = 0 Then
MessageBox.Show("Failed to add card.")
End If
End Using
You will need to change the .MySqlDbType and .Size to match how they are declared in the database.
I put backticks around the table name to escape it in case a reserved word is used or the name has spaces in it.
I changed the Functions to Properties in the Floshcods class and moved the InputBoxes to the User Interface code.
Public Class Floshcods
Public Property CardCodes As Integer
Public Property KeyWord As String
Public Property Definition As String
Public Sub New(ByVal CC As Integer)
CardCodes = CC
End Sub
End Class
I pulled out the data access code to separate methods so it will be easy to refactor to a data access layer. Also a method should be doing a single job and your Sub New was doing too much.
Using...End Using blocks ensure that your database objects are closed and disposed even if there is an error.
Always use parameters to avoid Sql injection. Datatypes are guesses. Check your database for the actual types.
Sub New()
Dim TableName = "SomeTableName"
Dim numb = GetMaxCarCode(TableName)
Dim cardcode As Integer = numb + 1
Dim p As New Floshcods(cardcode)
p.KeyWord = InputBox("Enter keyword")
p.Definition = InputBox("Enter definiton")
Controls("words0").Text = p.KeyWord
Controls("words1").Text = p.Definition
InsertFloshcods(TableName, p)
End Sub
Private Function GetMaxCarCode(Tablename As String) As Integer
Dim numb As Integer
Using cn As New MySqlConnection("Your connection string."),
cmd As New MySqlCommand($"Select MAX(CardCode) From {Tablename};", cn)
cn.Open()
numb = CInt(cmd.ExecuteScalar)
End Using
Return numb
End Function
Private Sub InsertFloshcods(TableName As String, f As Floshcods)
Using cn As New MySqlConnection("your connection String"),
cmd As New MySqlCommand($"Insert Into {TableName} (CardCode, Keyword, Definition) Values (#Code, #Keyword, #Def);", cn)
With cmd.Parameters
.Add("#Code", MySqlDbType.Int32).Value = f.CardCodes
.Add("#Keyword", MySqlDbType.VarChar).Value = f.KeyWord
.Add("#Def", MySqlDbType.VarChar).Value = f.Definition
End With
cn.Open()
cmd.ExecuteNonQuery()
End Using
End Sub

SQL parameter either integer value or dbnull pass to query

Can't get my query to work. I want to pass either integer value or dbnull to my query but in that form is not working. Below my code.
Query:
Using cmd As New SqlCommand("SELECT COUNT(*) FROM tbSuSubSections_Sentences WHERE FK_Sentence_Id = #FK_Sentence_Id And FK_SubSection_Id = #FK_SubSection_Id And FK_SubSubKategorie_Id=#FK_SubSubKategorie_Id", con)
Parameter set up based on which one i need:
If _FK_SubSubKategorie_Id = 0 Then
cmd.Parameters.AddWithValue("#FK_SubSubKategorie_Id", DBNull.Value)
Else
cmd.Parameters.AddWithValue("#FK_SubSubKategorie_Id", _FK_SubSubKategorie_Id)
End If
if _FK_SubSubKategorie_Id is set to DBNull as shown my query should change a bit instead this part:
And FK_SubSubKategorie_Id=#FK_SubSubKategorie_Id", con)
to
And FK_SubSubKategorie_Id IS NULL", con)
What is the right way to do?
that's entire SQL function:
#Region "Check if connection already exist"
Public Function CheckIfConnectionAlreadyExist(_FK_Sentence_Id As Integer, _FK_SubSection_Id As Integer, _FK_SubSubKategorie_Id As Integer) As Boolean
Dim result As Boolean
Dim strcon = New AppSettingsReader().GetValue("ConnectionString", GetType(String)).ToString()
Using con As New SqlConnection(strcon)
Using cmd As New SqlCommand("SELECT COUNT(*) FROM tbSuSubSections_Sentences WHERE FK_Sentence_Id = #FK_Sentence_Id And FK_SubSection_Id = #FK_SubSection_Id And FK_SubSubKategorie_Id=#FK_SubSubKategorie_Id", con)
cmd.CommandType = CommandType.Text
cmd.Parameters.AddWithValue("#FK_Sentence_Id", _FK_Sentence_Id)
cmd.Parameters.AddWithValue("#FK_SubSection_Id", _FK_SubSection_Id)
If _FK_SubSubKategorie_Id = 0 Then
cmd.Parameters.AddWithValue("#FK_SubSubKategorie_Id", DBNull.Value)
Else
cmd.Parameters.AddWithValue("#FK_SubSubKategorie_Id", _FK_SubSubKategorie_Id)
End If
con.Open()
Dim o As Integer = cmd.ExecuteScalar()
If o > 0 Then
result = True
Else
result = False
End If
con.Close()
End Using
End Using
Return result
End Function
#End Region
Just create one query string which both conditions have in common and change it regarding _FK_SubSubKategorie_Id afterwards. Then create the command:
Dim qry as String = "SELECT COUNT(*) FROM tbSuSubSections_Sentences WHERE FK_Sentence_Id = #FK_Sentence_Id And FK_SubSection_Id = #FK_SubSection_Id And FK_SubSubKategorie_Id {0}"
If _FK_SubSubKategorie_Id = 0 Then
qry = string.Format(qry," IS NULL")
Else
qry = string.Format(qry, "=#FK_SubSubKategorie_Id"
End if
Using cmd As New SqlCommand(qry, con)
...

"object reference not set to an instance of an object" while creating the authorization of the staff to use the application

I am trying to create the code as below and error saying "object reference not set to an instance of an object".
Public Shared Function bGetStaffCode(ByVal strUserName As String, ByVal conn As SqlConnection, ByRef strErr As String) As Boolean
' TODO: NotImplemented statement: ICSharpCode.SharpRefactory.Parser.AST.VB.OnErrorStatement
Try
'Dim bStaffCode As Boolean
Dim strSQL As String = "select count(*) from portal_BillFinderAccess where loginID = 'Elvis Tan '"
Dim myCommand As New SqlCommand
myCommand.Connection = conn
myCommand.CommandText = strSQL
'If CInt(myCommand.ExecuteScalar) = 0 Then
Dim myDA As New SqlDataAdapter(strSQL, conn)
Dim myDS As New DataSet
myDA.Fill(myDS, "count")
If myDS.Tables(0).Rows(0).Item(0).ToString = "0" Then
MessageBox.Show("You are not authorized to use this application!")
Return False
Else
Return True
End If
Catch err As Configuration.ConfigurationException
MessageBox.Show(err.Message)
Finally
End Try
End Function`

vb.net call the same function twice from button Event Click

This is my code on button event click function
Dim con As New Koneksi
DataGridView1.Rows.Add(con.getIdTambahBarang(cbBarang.Text), _
con.getNamaTambahBarang(cbBarang.Text), _
con.getHargaTambahBarang(cbBarang.Text), _
txtJumlah.Text)
This is my class Koneksi code :
Public Function getIdNamaHargaTambahBarang(ByVal namaBarang As String, ByVal params As String) As String
Dim id As String = ""
Dim nama As String = ""
Dim harga As String = ""
Try
bukaKoneksi()
cmd.Connection = con
cmd.CommandType = CommandType.Text
cmd.CommandText = "SELECT * FROM barang WHERE nama_barang like '" & namaBarang & "'"
reader = cmd.ExecuteReader
If (reader.Read()) Then
If params = "getNama" Then
nama = reader.GetString(1)
Return nama
End If
If params = "getHarga" Then
harga = reader.GetDouble(2).ToString
Return harga
End If
If params = "getId" Then
id = reader.GetString(0)
Return id
End If
End If
tutupKoneksi()
Catch ex As Exception
End Try
End Function
Public Function getIdTambahBarang(ByVal namaBarang As String) As String
Return getIdNamaHargaTambahBarang(namaBarang, "getId")
End Function
Public Function getNamaTambahBarang(ByVal namaBarang As String) As String
Return getIdNamaHargaTambahBarang(namaBarang, "getNama")
End Function
Public Function getHargaTambahBarang(ByVal namaBarang As String) As String
Return getIdNamaHargaTambahBarang(namaBarang, "getHarga")
End Function
Both of the code above, produces
'System.InvalidOperationException' occurred in System.Data.dll error.
When I debug it, the second call of con produces this error. It seems that in VB.NET, the instance class function only can called once at a time, any solution?
Consider refactoring your code. You're actually hitting the database 3 times, each with a LIKE clause, where you really only need to do this once.
Suggest something like this, which performs the same business logic that you've got, with only one call to your database. It's also got some SQL injection prevention.
Dim con As New Koneksi
Dim barang As Barang = Koneksi.GetBarang()
DataGridView1.Rows.Add(barang.id,
barang.nama, _
barang.harga, _
txtJumlah.Text)
Public Class Koneksi
Public Function GetBarang(nama_barang As String)
Dim barang As New Barang
bukaKoneksi()
cmd.Connection = con
cmd.CommandType = CommandType.Text
cmd.CommandText = "SELECT id,name,harga FROM barang WHERE nama_barang = #nama"
cmd.Parameters.AddWithValue("#nama", namaBarang)
reader = cmd.ExecuteReader
If (reader.Read()) Then
barang.id = reader.reader.GetString(0)
barang.nama = reader.GetString(1)
barang.harga = reader.GetDouble(2).ToString
End If
tutupKoneksi()
Return barang
End Function
End Class
You'll retrieve your barang object properties in one statement. All three properties are gathered from the DB at once. When you inevitably want to add another property to your DataGridView, you won't have to make any extra round-trips to your database, but rather only modify your SQL statement, and the .Rows.Add) call.
The database is now safe from SQL injection in this call.
the code is easier to read and understand for the next developer coming into read this code.
the database was previously using more resources due to being called 3x, and using a LIKE clause, where you really only needed an = name.