'Fill: SelectCommand.Connection property has not been initialized.' - vb.net

I am using a visual studio 2022 vb.net and mssql management studio.
login form
Private Sub Btnlogin_Click(sender As Object, e As EventArgs) Handles Btnlogin.Click
cn.Open()
cm = New SqlClient.SqlCommand("select * from table_user where username like '" & username.Text & "' and password like '" & password.Text & "'and usertype= '" & usertype.SelectedItem & "'", cn)
dr = cm.ExecuteReader
sda.Fill(dt)
If (dt.Rows.Count > 0) Then
MessageBox.Show("You are login as " + dt.Rows(0)(2))
If (usertype.SelectedIndex = 0) Then
Dim a As New dashboard
a.Show()
Me.Hide()
Else
Dim b As New Admin
b.Show()
Me.Hide()
End If
Else
MessageBox.Show("Username or Password Incorrect. CONTACT ADMINISTRATOR!")
End If
cn.Close()
End Sub
Module
Imports System.Data.SqlClient
Module Module1
Public cn As New SqlConnection("Data Source=DESKTOP-7POF5HE\SQLEXPRESS;Initial Catalog=dict;Integrated Security=True")
Public cm As New SqlCommand
Public dr As SqlDataReader
Public sda As SqlDataAdapter = New SqlDataAdapter(cm)
Public dt As DataTable = New DataTable()
End Module
CAN YOU HELP ME TO SOLVE THIS?

Seems there are several issues with this code.
In your module, you create the command object and the data adapter object. But in the form method, you create a new command object. But that will not update the data adapter to use that new command object. Class variables are reference types. They just point to an object in the memory somewhere. Your cm variable will point to the new command object, but your sda object will internally still point to the old command object.
Furthermore:
You are using both a data reader and a data adapter. Both have their pros and cons, but you probably don't need (or want) to use them both at the same time. I assume you want to use the data adapter. So you can drop the dr = cm.ExecuteReader line in the form method.
Since you will probably always want to create command objects and data adapter objects on the fly (as I would), you could remove them from the module. Just create them both as local variables in your form method.
Try to use the Using statement for such objects. They need to be disposed of nicely when the form method finishes. Otherwise they might keep valuable system resources in use until the .NET garbage collector disposes them (which will probably occur when you close your application, not earlier).
Also be careful with concatenating SQL statements from variables. What would happen here if you enter this text in your username textbox?: ';delete from table_user;--
Hint: Do not actually try it! It will try to delete all your users from the database table table_user. Just try to manually reproduce the SQL string that will be built in your form method. This is called an SQL injection attack. To avoid such nasty things, it's easiest to use SQL parameters in your SQL statements and pass them separately to your command object.

Related

Autofill textboxes from access database based on one text box value

I have 3 text boxes and based on Customer Name suggestion other 2 boxes should be auto filled
I am new to database so I am finding codes on internet and trying to implement it but it
is not working. So please help me with this.
I am working in for Windows Form Application in visual basic.
Private Sub AutoComplete()
'sql = "Select * FROM Table1 where CustomerName='" & custnm.Text & "'"
com = New OleDbCommand(sql, con)
reader = com.ExecuteReader()
Dim autoComp As New AutoCompleteStringCollection()
While reader.Read()
autoComp.Add(reader("CustomerName"))
autoComp.Add(reader("ContactNO"))
End While
reader.Close()
custnm.AutoCompleteMode = AutoCompleteMode.Suggest
custnm.AutoCompleteSource = AutoCompleteSource.CustomSource
custnm.AutoCompleteCustomSource = autoComp
contactno.AutoCompleteMode = AutoCompleteMode.Suggest
contactno.AutoCompleteSource = AutoCompleteSource.CustomSource
contactno.AutoCompleteCustomSource = autoComp
wcontno.AutoCompleteMode = AutoCompleteMode.Suggest
wcontno.AutoCompleteSource = AutoCompleteSource.CustomSource
wcontno.AutoCompleteCustomSource = autoComp
End Sub
This is only a partial solution to straighten out your database code. It is too much code to put in a comment.
Keep your database objects local so you can control when they are closed and disposed. Objects that expose a .Dispose method may have unmanaged resources that need to be released. A Using...End Using block will handle this for you even if there is and error.
Always use Parameters to avoid sql injection which can damage your database. Also it makes the sql string easier to write. You will need to check your database for the proper datatype because I had to guess.
A DataReader uses an open connection until it is done. You don't want to hold your connection open while you use the data so I chose a DataTable. Just load it and pass it off to where you want to use it. The connection and command are closed and disposed.
I wasn't sure why you combined the data in a single AutoCompleteStringCollection. It seems that one for each combo box would be better. They are form level variables so you can used them in another method to attach to a combo box.
I think you need to look into BindingSource and BindingNavigator to sync the combo boxes.
Private Function GetData() As DataTable
Dim dt As New DataTable
Using con As New OleDbConnection("Your connection string"),
com As New OleDbCommand("Select * FROM Table1 where CustomerName= #Name;", con)
com.Parameters.Add("#Name", OleDbType.VarChar).Value = custnm.Text
con.Open()
dt.Load(com.ExecuteReader)
End Using
Return dt
End Function
Private autoCompName As New AutoCompleteStringCollection()
Private autoCompNO As New AutoCompleteStringCollection()
Private Sub FillAutoCompleteCollection()
Dim dt = GetData()
For Each row As DataRow In dt.Rows
autoCompName.Add(row("CustomerName").ToString)
autoCompNO.Add(row("ContractNO").ToString)
Next
End Sub

ComboBox.SelectedText Property and Database Error

This specific code ComboBox2.SelectedItem query has an error to my database. I think I'm missing something with this code ComboBox2.SelectedItem:
Private Sub UpdateCombo()
ComboBox2.Items.Clear()
SQLcon.Open()
Dim Command As SqlClient.SqlCommand = SQLcon.CreateCommand()
Command.CommandText = "Select productName From tblProductsStocks"
Dim SQLReader As SqlClient.SqlDataReader = Command.ExecuteReader()
While SQLReader.Read()
ComboBox2.Items.Add(SQLReader.Item("productName"))
End While
SQLcon.Close()
End Sub
Private Sub ComboBox2_SelectedIndexChanged(sender As Object, e As EventArgs) Handles ComboBox2.SelectedIndexChanged
SQLcon.Open()
Dim Command As SqlClient.SqlCommand = SQLcon.CreateCommand()
Command.CommandText = "Select * From tblProductsStocks WHERE productName=" & ComboBox2.SelectedItem
Dim SQLReader As SqlClient.SqlDataReader = Command.ExecuteReader()
SQLReader.Read()
TextBox1.Text = SQLReader.Item("productType")
TextBox2.Text = SQLReader.Item("productMass")
SQLcon.Close()
End Sub
Please turn on Option Strict. This is a 2 part process. First for the current project - In Solution Explorer double click My Project. Choose Compile on the left. In the Option Strict drop-down select ON. Second for future projects - Go to the Tools Menu -> Options -> Projects and Solutions -> VB Defaults. In the Option Strict drop-down select ON. This will save you from bugs at runtime.
Connections need to be disposed as well as closed to be returned to the connection pool. If there is an error, your code may not even close the connection. If you keep your database objects local, you can control that they are closed and disposed. Using...End Using blocks take care of this for you even if there is an error. In my code the Command is part of the Using block. Note the comma after the connection constructor.
You can pass the connection string directly to the constructor of the connection. Likewise pass the command text and the connection to the command constructor.
Use parameters. Not only does it avoids errors concatenating strings but it also avoids Sql injection. In your code, the selected item is meant to be a string but you have failed to add the surrounding single quotes. This is not needed when you use parameters. Command text is executable code to the server and a malicious user can enter things that would ruin you database. Parameters are considered as values by the server, not executable code so they are much safer.
Open the connection at the last possible moment, right before the .Execute... Connections are precious resources and need to be opened, closed and disposed as quickly as possible. The connection must be open as long as the reader is engaged. So I moved updating the user interface (the text boxes) to outside the using block.
Private Sub ComboBox2_SelectedIndexChanged(sender As Object, e As EventArgs) Handles ComboBox2.SelectedIndexChanged
Dim String1 As String = ""
Dim String2 As String = ""
Using SQLcon As New SqlConnection("Your connection string"),
Command As New SqlCommand("Select * From tblProductsStocks WHERE productName= #producName", SQLcon)
'Check your database for the actual datatype and field size
Command.Parameters.Add("#productName", SqlDbType.VarChar, 100).Value = ComboBox2.SelectedItem.ToString
SQLcon.Open()
Dim SQLReader As SqlClient.SqlDataReader = Command.ExecuteReader()
SQLReader.Read()
String1 = SQLReader.Item("productType").ToString
String2 = SQLReader.Item("productMass").ToString
End Using 'closes and disposes the connection and command
TextBox1.Text = String1
TextBox2.Text = String2
End Sub

How to make connection VFP database with VB.NET

I'm creating a system that use foxpro as a database. I keep getting this error error [42S02][microsoft][ODBC visual foxpro driver] not a table when I want to connect VFP database with Visual Studio. When I add data connection in the visual studio, it shows connection success, but when I try to open the table, it shows the error.
This is a VB.Net system that use database foxpro 9. I have use mysql as the database and it work, but when I try to use foxpro database I get an error.
Imports System.Data.Odbc
Imports System.Data.OleDb
Public Class login
Private Sub btnEnter_Click(sender As Object, e As EventArgs) Handles btnEnter.Click
Dim oConn = CreateObject("adodb.connection")
oConn.ConnectionString = "Provider=vfpoledb;DSN=visual_foxpro"
oConn.Open()
Dim conn = New OleDbConnection()
Dim cmdString As String = "SELECT * FROM `login` WHERE `staffID`= #staffid AND `staffName`= #staffname"
Dim cmd As New OleDbCommand(cmdString, oConn)
cmd.Parameters.Add(New OleDbParameter("staffID", CType(txtStaffID.Text, String)))
cmd.Parameters.Add(New OleDbParameter("staffName", CType(txtStaffID.Text, String)))
Dim adapter As New OleDbDataAdapter(cmd)
Dim table As New DataTable()
adapter.Fill(table)
If table.Rows.Count = 0 Then
MessageBox.Show("Staff ID or Staff Name not available")
Else
MessageBox.Show("Welcome " & txtStaffName.Text)
Dim form As New formLeave
form.PassStaffid = txtStaffID.Text
form.PassStaffName = txtStaffName.Text
form.Show()
Me.Hide()
End If
End Sub
End Class
I expected the system can login using the database.
VFP database versions later than 6.x do not have an official ODBC driver from Microsoft. If you HAVE TO use ODBC, then you can find alternative drivers from sources like Sybase ADS. I use OLEDB instead successfully well.
While your code might work with MySQL, that is not the way you should write it. Also, it is MySQL specific, it wouldn't work in say MS SQL Server or postgreSQL either. You should read the documentation on the backend you are using. In VFP (or MS SQL Server, postgreSQL ...), you don't use back tics as table and field name identifiers. In VFP, if need be, to use name identifiers you could use single, double quotes or square brackets but you would need to enclose with parentheses (and use only for table name in an SQL query). Anyway, the easy way is to simply not to use identifiers at all.
Also, with an ODBC or OLEDB query, you need to use ? as parameter placeholders. Using #staffID wouldn't normally work in MySQL, ... either, but driver makers decided to support them for those backends.
From your messageBox messages, looks like you expect to get a single row for that query (I don't know why you use both staffId and staffName if staffId is primary key). Anyway here is your query in VB.Net:
Imports System.Data.OleDb
Public Class login
Private Sub btnEnter_Click(sender As Object, e As EventArgs) Handles btnEnter.Click
Dim strConn As String = "Provider=VFPOLEDB;Data source=c:\MyDataFolder\"
Dim strQuery As String = <sql>SELECT *
FROM login
WHERE staffID=? AND staffName=?
</sql>
Using cn As New OleDbConnection(strConn)
Using cmd As New OleDbCommand(strQuery, cn)
cmd.Parameters.Add("#staffid", OleDbType.VarChar).Value = txtStaffID.Text;
cmd.Parameters.Add("#staffname", OleDbType.VarChar).Value = txtStaffName.Text;
cn.Open()
Dim rdr As OleDbDataReader = cmd.ExecuteReader()
If rdr.Read()
MessageBox.Show("Welcome " & txtStaffName.Text)
Dim form As New formLeave
form.PassStaffid = txtStaffID.Text
form.PassStaffName = txtStaffName.Text
form.Show()
Me.Hide()
Else
MessageBox.Show("Staff ID or Staff Name not available")
End If
cn.Close()
End Using
End Using
End Sub
End Class

GUID format not recognized (when is null)

In my application I create a function that allow the user to change the settings of the app. This settings are stored into a table 'cause there's a lot of records. Anyway, the problem's that if the settings isn't valorized yet, when the application start and load the settings from the table take of course a null GUID field and the message:
GUID format not recognized
appear. A code explaination:
Sub LoadSettings()
Using dbCon As MySqlConnection = establishConnection()
Try
dbCon.Open()
Dim MysqlCommand = New MySqlCommand("SELECT * FROM settings", dbCon)
Dim reader = MysqlCommand.ExecuteReader
For Each row In reader
Select Case row(2)
Case "company_name"
Setting.name.Text = row(3)
Case "company_email"
Setting.email.Text = row(3)
...
End Select
Next
End Sub
This function is called when the settings form is opened. If the settings aren't inserted yet, I get a message of bad format. I want to know how I can avoid this message.
You are not using the DataReader correctly. Consider this code:
Dim reader = MysqlCommand.ExecuteReader
For Each row In reader
... something
Next
MysqlCommand.ExecuteReader returns a DataReader object, but it is not - nor does it contain - a row collection you can iterate. If you hold the mouse over row you should see that it is a Data.Common.DataRecordInternal object which does have an Item property but a reference like row(2) will only compile with Option Strict Off.
Used correctly, when you Read a row the data in that internal object is available via the indexer (Item) and the various Getxxxxx() methods. This just prints the Id and Name from a table in a loop. I cant quite tell what you are trying to do with your results...it sort of looks like a Name/Value pair type thing maybe.
Dim SQL = "SELECT * FROM Demo"
Using dbcon = GetMySQLConnection(),
cmd As MySqlCommand = New MySqlCommand(SQL, dbcon)
dbcon.Open()
Using rdr As MySqlDataReader = cmd.ExecuteReader
If rdr.HasRows Then
Do While rdr.Read()
Console.WriteLine("{0} - {1}", rdr("Id").ToString, rdr("Name").ToString)
Loop
End If
End Using ' dispose of reader
End Using ' dispose of Connection AND command object
Alternatively, you could fill a DataTable and iterate the rows in that. Seems 6:5 and pick-em whether that would gain anything.
Note also that the Connection, Command and DataReader objects are properly disposed of when we are done using them.

how to populate items from database in a listbox in vb.net

I was developing an application using oop concept.I have a class that has 2 attributes and have Get and Set methods namely WorkItemNumber and Description.
On the client side i have a list box used to populate the work items based on their description.Here's the code i wrote in the class o read items from the database.
Public Sub LoadWorkItem()
' Load the data.
' Select records.
Dim oWorkItem As WorkItem = New WorkItem()
Dim conn As New OleDbConnection
Dim data_reader As OleDbDataReader
conn = oWorkItem.GetDbConnection()
Dim cmd As New OleDbCommand("SELECT * FROM work_item ORDER BY [work item number]", conn)
data_reader = cmd.ExecuteReader()
'ListBox1.Items.Clear()
If data_reader.HasRows = True Then
Do While data_reader.Read()
WorkItemNumber = data_reader.Item("work item number")
Description = data_reader.Item("description")
Loop
End If
data_reader.Close()
data_reader = Nothing
cmd.Dispose()
cmd = Nothing
conn.Close()
conn.Dispose()
End Sub
How do i populate the listbox using the code,and if there's any improvement on the code please do tell me as well.Thank you
To poulate your ListBox, do this...
ListBox1.Item.Clear()
If data_reader.HasRows Then
Do While data_reader.Read()
WorkItemNumber = data_reader.Item("work item number")
Description = data_reader.Item("description")
ListBox1.Items.Add(New ListItem(Description, WorkItemNumber)
Loop
End If
As far as improvements, start by using a Using statement for the DB connection. In your code, if there is an exception while the database connection is open, it will never get closed. This is better...
Using conn As OleDbConnection = oWorkItem.GetDbConnection()
' Execute SQL and populate list...
End Using
The above code assures that your connection will be closed.
Then, turn on Option Strict and Option Explicit. This will force you to declare the Type for Description and WorkItemNumber and cast them as Strings when adding a ListItem. This will reduce run-time errors.
Finally, if this is anything but a small app you are doing as a learning experiment, you should read up on tiered application design. Your code is mixing UI, business logic, and data access in the same method. This is generally frowned upon.
Your "user interface" LoadWorkItem() method should ask a "core" method for a list of WorkItems.
Your core method should then ask a "data access" method for data.
The "data access" method should make the call to the database.
Happy coding.
Update: You can find excellent info about n-Tier architecture on MSDN. A good book to read once you grasp the fundamentals and have some confidence in .NET is Visual Basic .NET Business Objects.
Imports System.Data.SqlClient 'Reference The Sql Client
Public Class Form1
''Make sure to change the connection string below to your connection string this code only works for SQL DataBase. If Your connection String is wrong This will Not Work
Dim connString As String = "Data
Source=NameofYourSQLServer\SQLEXPRESS;Initial Catalog=NameOfYourDataBase;Integrated Security=True"
Dim tblDIV As DataTable
Dim daDIV As SqlDataAdapter
Dim dsDIV As New DataSet
Dim oCon As SqlConnection
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim oCon = New SqlConnection
oCon.ConnectionString = connString
dsDIV = New DataSet
' Select all Fields and order by ID or Replace * with name of Field
daDIV = New SqlDataAdapter("SELECT * FROM NameOfYourTable ORDER BY Id DESC", oCon)
'*** Define command builder to generate the necessary SQL
Dim builder As SqlCommandBuilder = New SqlCommandBuilder(daDIV)
builder.QuotePrefix = "["
builder.QuoteSuffix = "]"
Try
daDIV.FillSchema(dsDIV, SchemaType.Source, "DIV")
daDIV.Fill(dsDIV, "DIV")
tblDIV = dsDIV.Tables("DIV")
ListBox1.DataSource = tblDIV
ListBox1.DisplayMember = "NameOfTheFieldYouWanttoDisplay"
Catch ex As Exception
MsgBox("Encountered an Error;" & vbNewLine & ex.Message)
oCon.Close()
End Try
End Sub