"InvalidOperationException : Connection must be valid and open" On MySqlConnection - mysql

I was working on a VB.Net project (first time, I was previously working in VBA) and I seem to have trouble establishing connecion with a MariaDB/MySQL database.
I wanted to get all rows for one column to use it as source for a ComboBox named CBClient in a Form
Here my codes so far:
First class: ClassSQL
Imports MySql.Data.MySqlClient
Imports MySql.Data.Types
Public Class ClassSQL
Public Shared ConfigSQL As String =
"DATABASE=(My actual DB);DATA SOURCE=(IP of the server);USER ID=(UserID);PASSWORD=(Password)"
Public Shared ConnectDB As New MySqlConnection(ConfigSQL)
End Class
And the Form class:
Imports MySql.Data.MySqlClient
Public Class NewDossier
Private Sub NewDossier_Load(sender As Object, e As EventArgs) Handles MyBase.Load
GetCBClient()
End Sub
Sub GetCBClient()
ClassSQL.ConnectDB.Open()
Dim Requete As String = "SELECT NomClient FROM MSClients"
Dim Query As New MySqlCommand(Requete, ClassSQL.ConnectDB)
Dim rs As MySqlDataReader = Query.ExecuteReader
Do While rs.Read
CBClient.Items.Add(rs.GetString("NomClient"))
Loop
ClassSQL.ConnectDB.Close()
End Sub
End Class
On ClassSQL.ConnectDB.Open() in the Form class I have the exception:
InvalidOperationException : Connection must be valid and open
Is my connection wrong somehow? Or is it something I did wrong?
Is there a way to specify the port?

In ADO.Net, it is not generally a good idea to try to re-use the same connection object throughout an application, because of a feature called Connection Pooling. The connector is already managing this for you. Instead, it really is better to just create a new connection instance for most queries. Just keep the connection string handy and re-use that. This works especially well in conjunction with the IDisposable/Using pattern.
Additionally, it's a good idea to put your queries in the same Class or Module as your connection string, isolated from the rest of the application, where each query is a function that returns the data and (usually) accepts an argument telling it what data to find.
Public Module SQL
'Making this private helps ensure you remember to put database activities here in this class.
Private ConnectionString As String = "DATABASE=(My actual DB);DATA SOURCE=(IP of the server);USER ID=(UserID);PASSWORD=(Password)"
'You could also design this function to return a DataTable object, if Iterator blocks aren't your thing
Public Iterator Function GetMSClients() As IEnumerable(Of String)
Dim Requete As String = "SELECT NomClient FROM MSClients"
Using cn As New MySqlConnection(ConnectionString), _
cmd As New MySqlCommand(Requete, cn)
cn.Open()
Using rdr As MySqlDataReader = cmd.ExecuteReader()
While rdr.Read()
Yield rdr.GetString("NomClient")
End While
End Using
End Using
End Function
End Module
Public Class NewDossier
Private Sub NewDossier_Load(sender As Object, e As EventArgs) Handles MyBase.Load
CBClient.Items.AddRange(SQL.GetMSClients().ToArray())
End Sub
End Class

Related

retrieve text in my mySql database and put into texbox using ODBC in vb.net

I want to retrieve a question from my db and put it into textbox for security questions but I don't know how. I am using ODBC as connection in vb.net into mysql.
Here is my code
Imports System.Data.Odbc
Public Class forgPass
Dim con As New OdbcConnection("DSN=nohdb")
Dim com As New OdbcCommand
Dim dt As DataTable
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
con.Open()
com = New OdbcCommand("SELECT question1 FROM sec_questions WHERE='admin'", con)
dt = New DataTable
dt.Load(com.ExecuteReader)
ques1.Text = dt.ReadXml
con.Close()
End Sub
End Class
You need to add
Imports MySql.Data.MySqlClient
I am assuming the following
You can insert the correct connection string in the con constructor. See
https://www.connectionstrings.com/mysql-connector-net-mysqlconnection/
for reference.
question1 is the name of a field in your database table.
sec_questions is the name of a table in your database.
Replace SomeFieldName with the name of field where admin is
found.
Keep your database objects local so you can control that they are closed and disposed. A single Using...End Using block handles this for you even if there is an error.
The user interface is not updated until the database objects are closed and disposed with the End Using.
To retrieve data from the DataTable you can refer to the first row in the Rows collection which is index 0. Then the column name, question1. Since the datatype is unknown until runtime we call .ToString to satisfy Option Strict.
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim dt As New DataTable
Using con As New MySqlConnection("Your connection string"),
com As New MySqlCommand("SELECT question1 FROM sec_questions WHERE SomeFieldName ='admin';", con)
con.Open()
dt.Load(com.ExecuteReader)
End Using
ques1.Text = dt.Rows(0)("question1").ToString
End Sub

MySQL Query Execution with Visual Basic

I am attempting to make a connection to MySQL server, take input from a text box, the use the information to run query and store it in a listbox.
To go even further I would like to and make the listbox update as I type in the text box.
Whenever I run run the vb nothing populates. I even tried changing the query to something basic, select * from securePasswordList.users; And I can't get anything to populate.
Any suggestions or criticism? THanks! Still learning quite a bit about VB...and a long ways to go.
Imports MySql.Data.MySqlClient
Public Class Reveal
Public Property MyDataClass As SecurePasswordList
Dim lastNameInput As String
Dim firstNameInput As String
Dim connStr As String = "server=0.0.0.0;user=johndoe;database=securePasswordList;port=3306;password=password;"
Dim conn As New MySqlConnection(connStr)
Dim SQL As String = "select password from securePasswordList.users where LAST_NAME like ' " & lastNameInput & "%'"
Dim cmd As MySqlCommand = New MySqlCommand(SQL, conn)
Private Sub Reveal_Load(sender As Object, e As EventArgs) Handles MyBase.Load
End Sub
Private Sub firstName_TextChanged(sender As Object, e As EventArgs) Handles lastNameTextBox.TextChanged
lastNameInput = lastNameTextBox.Text
listBox.Items.Add(cmd)
End Sub
Private Sub lastName_TextChanged(sender As Object, e As EventArgs) Handles firstNameTextBox.TextChanged
firstNameInput = firstNameTextBox.Text
End Sub
Private Sub listBox_SelectedIndexChanged(sender As Object, e As EventArgs) Handles listBox.SelectedIndexChanged
End Sub
End Class
One of your issues is that you are not actually executing the MySqlCommand anywhere. Also, I would like to point you to this link, since you have a potential security issue in your current code in the way you build your select-string.
Here is an example of how you could retrieve a password:
Private Function RetrievePassword(ByVal lastName As String) As String
Using conn As New MySqlConnection(connStr)
Using comm As New MySqlCommand(query, conn)
comm.Parameters.AddWithValue("#LastName", lastName & "%'")
Dim result As Object = comm.ExecuteScalar()
If result Is Nothing Then
handle as you like...
End If
Return result.ToString
End Using
End Using
End Function
query would contain a placeholder for the parameter like so:
Private Const query As String =
"select password from securePasswordList.users where LAST_NAME like #LastName"

Add Multiple Databases in VB.NET

Is it possible to connect multiple databases to a program?
I added a database, but it was always through the "Data Source Config Wizard". My application deals with one main database, but I need to load information from other databases and add it to the main one (the user will select which database through the OpenFileDialog).
Public Class Form1
Private Sub TblTestBindingNavigatorSaveItem_Click(sender As Object, e As EventArgs) Handles TblTestBindingNavigatorSaveItem.Click
Me.Validate()
Me.TblTestBindingSource.EndEdit()
Me.TableAdapterManager.UpdateAll(Me.TestdbDataSet)
End Sub
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
'TODO: This line of code loads data into the 'TestdbDataSet.tblTest' table. You can move, or remove it, as needed.
Me.TblTestTableAdapter.Fill(Me.TestdbDataSet.tblTest)
End Sub
Private Sub btnLoad_Click(sender As Object, e As EventArgs) Handles btnLoad.Click
Dim DBConnection As New OleDb.OleDbConnection
'''' Dim con As New OleDb.OleDbConnection
Dim dbProvider As String = "Provider=Microsoft.ACE.OLEDB.12.0;"
'Dim dbSource As String = opnFile.ShowDialog()
opnFile.ShowDialog()
Dim ex As String = opnFile.FileName
MessageBox.Show(ex)
Dim dbSource As String = "DataSource=" & ex
MessageBox.Show(dbSource, "Data Source String", MessageBoxButtons.OK, MessageBoxIcon.Information, MessageBoxDefaultButton.Button1)
Dim DBDataSet As New DataSet
'''' Dim ds As New DataSet
Dim DBDataAdapter As OleDb.OleDbDataAdapter
'''' Dim da As OleDb.OleDbDataAdapter
DBConnection.ConnectionString = dbProvider & dbSource
'DBDataAdapter = (sql, DBConnection)
End Sub
End Class
Also, can someone explain to me the link in DataAdapter, DataConnection, and the DataSet? From what I see, the DataConnection is just the link that will connect the application to the database. The DataSet is your actual data from the database. So what is the DataAdapter for?
Thanks for any help!
You can add several databases using the Database wizard. You will be missing the binding navigator but you can get this easily by creating a temporary form in your project add the database to this then just copy over the binding navigator before deleting the temp form.
See this thread Display data from access using dataset The use the following.
Try something like this after you load your table into a Dataset
For Each row1 In (From dr As DataRow In yourDataSet.Tables(0).Rows Select dr Where dr("Column_Name").ToString.StartsWith(yourstring)
somestring = row1("Column_Name").ToString

Access to MySQL after closing connection

I have a problem with access to my datebase MySQL after closing it. I use Windows Form and MySql Connector from MySql official website to connect to datebase. I use MySQL in XAMPP.
If I open my connection I can do a simple query. But when I close a connection I can still do this query. Why?
Here is my code:
Imports MySql.Data.MySqlClient
Public Class Form1
Dim polaczenieMySql As New MySqlConnection
Dim mySQL As PolaczenieMySQL
Public Sub New()
InitializeComponent()
mySQL = New PolaczenieMySQL(Me)
End Sub
Private Sub btnPolaczMySQL_Click(sender As Object, e As EventArgs) Handles btnPolaczMySQL.Click
mySQL.Polacz()
End Sub
Private Sub RozlaczMySQL_Click(sender As Object, e As EventArgs) Handles btnRozlaczMySQL.Click
mySQL.Rozlacz()
End Sub
Private Sub btnZapytanie_Click(sender As Object, e As EventArgs) Handles btnZapytanieMySQL.Click
Dim zapytanie As String = "SELECT title, price, book_id from books"
mySQL.WykonajZapytanie(zapytanie)
End Sub
End Class
And my connection class:
Imports MySql.Data.MySqlClient
Public Class PolaczenieMySQL
Dim polaczenie As MySqlConnection = New MySqlConnection()
Dim glowneOkno As Form1
Public Sub New(form As Form1)
glowneOkno = form
End Sub
Public Sub Polacz()
polaczenie.ConnectionString = ("server=localhost;user id=root;password=;database=test")
Try
polaczenie.Open()
MessageBox.Show("Połączono z bazą danych MySQL.")
glowneOkno.labelPolaczenieMySQL.Text = "Połączono"
glowneOkno.labelPolaczenieMySQL.ForeColor = Color.Green
Catch myerror As MySqlException
MessageBox.Show("Nie udało się połączyć z bazą danych MySQL: " & myerror.Message)
End Try
End Sub
Public Sub Rozlacz()
Try
polaczenie.Close()
MessageBox.Show("Rozłączono z bazy danych MySQL.")
glowneOkno.labelPolaczenieMySQL.Text = "Nie połączono"
glowneOkno.labelPolaczenieMySQL.ForeColor = Color.Red
Catch myerror As MySqlException
MessageBox.Show("Błąd rozłączenia z bazy danych MySQL: " & myerror.Message)
Finally
polaczenie.Dispose()
End Try
End Sub
Public Sub WykonajZapytanie(ByVal zapytanie As String)
Dim SDA As New MySqlDataAdapter
Dim dbDataSet As New DataTable
Dim bSource As New BindingSource
Try
Dim komenda As MySqlCommand = New MySqlCommand(zapytanie, polaczenie)
SDA.SelectCommand = komenda
SDA.Fill(dbDataSet)
bSource.DataSource = dbDataSet
glowneOkno.DataGridViewMySQL.DataSource = bSource
SDA.Update(dbDataSet)
Catch ex As MySqlException
MessageBox.Show("Nie jesteś połączony z bazą")
End Try
End Sub
End Class
As I said before, after closing connection (mySQL.Rozlacz()) I can still do a query (mySQL.WykonajZapytanie(zapytanie)). What is wrong with this?
PS. Sorry for my polish names
If you look at the docs about the DbDataAdapter you could read this remark
The Fill method retrieves the data from the data source using a SELECT
statement. The IDbConnection object associated with the select command
must be valid, but it does not need to be open. If the IDbConnection
is closed before Fill is called, it is opened to retrieve data and
then closed. If the connection is open before Fill is called, it
remains open.
The MySqlDataAdapter inherits from the DbDataAdapter and there is no override of the Fill method, so it is the inherited class (DbDataAdapter) that works with the associated command, reopening the closed connection and then closing it.
EDIT
You asked also how to avoid this behavior, well you could add a boolean property to your class PolaczenieMySQL that maintains the state of your MySqlConnection
Private _isDead As Boolean
Public Property IsDead() As Boolean
Get
Return _isDead
End Get
Private Set(ByVal value As String)
_isDead = value
End Set
End Property
Now you could set this property to False when you open the connection and True when you close it.
Then check its value before executing the WykonajZapytanie sub
Public Sub WykonajZapytanie(ByVal zapytanie As String)
Dim SDA As New MySqlDataAdapter
Dim dbDataSet As New DataTable
Dim bSource As New BindingSource
if Me.IsDead Then
Throw new Exception("Invalid usage of this class")
End If
......
End Sub
Notice that there is a simpler check using the MySqlConnection property State
if polaczenie.State <> ConnectionState.Open Then
......
but, given the fact that in your Rozlacz method you dispose the connection I suggest to implement the first workaround.
Finally, I really think that you should change the whole pattern of usage. The connection should be opened, used and closed in the same method where it is required. Your actual infrastructure render this impossible. It is better to get rid of the Polacz and Rozlacz and use the mentioned pattern without the need of a global variable for the connection.

VB.Net reuse sql connection

I'm a newbie to vb.net, I'd like to ask is there a way to reuse the sql connection command?
Here is the code for my main.vb:
Dim ServerString As String = "Server=localhost;User Id=root;Password=;Database=pos"
Dim SQLConnection As MySqlConnection = New MySqlConnection
Private Sub Main_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
SQLConnection.ConnectionString = ServerString
Try
If SQLConnection.State = ConnectionState.Closed Then
SQLConnection.Open()
Else
SQLConnection.Close()
End If
Catch ex As Exception
MsgBox(ex.ToString)
End Try
Since I'd like to use this in my other classes, i don't want to re-write this code in every form. Any help is truly appreciated. Thanks.
Reusing a connection (or any other unmanaged resource) is normally not a good idea. You should dispose them as soon as possible.
But there's no problem in always creating a new connection anyway, since you're using the ADO.NET connection-pool by default. So you are not creating (and opening) a new physical connection. Actually you're just telling the pool that a conenction is reusable somewhere else now when you close/dispose it. And when you open it, it cannot be used somewhere else, that's why it's important to always close it.
Therefore always use the Using-statement.
Public Shared Function GetColumn1(column2 As Int32) As String
Dim sql = "SELECT Column1 From dbo.tableName WHERE Column2=#Column2 ORDER BY Column1 ASC"
Using con = New SqlConnection(connectionString)
Using cmd = New SqlCommand(sql, con)
cmd.Parameters.AddWithValue("#Column2", column2)
Try
con.Open()
Using rd = cmd.ExecuteReader()
If rd.Read() Then
Dim Column1 As String = rd.GetString(0)
Return Column1
Else
Return Nothing
End If
End Using
Catch ex As Exception
' log the exception here or do not catch it '
' note that you don't need a Finally to close the connection '
' since a Using-Statement disposes the object even in case of exception(which also closes a connection implicitely)
End Try
End Using
End Using
End Function
Above is a sample method to demontrate that you should not reuse anything.
This is what I normally do: I create a class, e.g. ConnectDB, and a method within this class, e.g. GetConnection. Here is the code:
Imports System.Data
Imports System.Data.SqlClient
Public Class ConnectDB
Public Shared Function GetConnection() As SqlConnection
Dim dbConnString As String = "Data Source=(local);Initial Catalog=Northwind;Integrated Security=True"
Return New SqlConnection(dbConnString)
End Function
End Class
Then from the method that needs a connection to the database, I call this function. Here is a sample code:
Imports System.Data.SqlClient
Public Class EmployeeDB
Public Shared Function GetEmployees() As List(Of Employee)
Dim con As SqlConnection = ConnectDB.GetConnection()
Dim selectStmt As String = "SELECT * FROM Employees"
Dim selectCmd As New SqlCommand(selectStmt, con)
Dim employees As New List(Of Employee)
Try
con.Open()
Dim reader As SqlDataReader = selectCmd.ExecuteReader()
Do While reader.Read
Dim employee as New Employee
employee.LastName = reader("LastName").ToString
employee.FirstName = reader("FirstName").ToString
...
employees.Add(employee)
Loop
reader.Close()
Catch ex As Exception
Throw ex
Finally
con.Close()
End Try
Return employees
End Function
End Class
You can also modify the selectStmt string to include filter conditions, parameters, and sort order just like Tim's example above and include selectCmd.Parameters.AddWithValue("#<parameterName>", value) for each of your parameters.