Access to MySQL after closing connection - mysql

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.

Related

VB.NET function return error and exit sub

I have this connection function in my VB.NET project
Public Function OpenMysqlCon() As MySqlConnection
Dim mMysqlconnection = New MySqlConnection()
Try
Dim strconDB As String = "server='192.168.100.2'; database='mydb';Port=3306; UID='epb'; password='hahaha'; pooling=true"
mMysqlconnection = New MySqlConnection
mMysqlconnection.ConnectionString = strconDB
mMysqlconnection.Open()
OpenMysqlCon = mMysqlconnection
Catch exceptionThatICaught As System.Exception
OpenMysqlCon = Nothing
End Try
End Function
And i will call the function in my VB project something like
Private Sub frmTest_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Using Con=OpenMysqlCon()
'mycode here
End Using
End Sub
However when the connection is not available, it will throw an exception.
How can i avoid the exception by giving a msgbox something like connection not available at the moment, please try again later and then exit the sub that was using the function?
End Sub
The best approach is to not hold the connection in a field of the form but to create and initalize it wherever you need it. The connection-pooling will ensure that no physical connection needs to be created.
So don't use a OpenMysqlCon method at all but code like this(GetAllUsers is just an example):
Public Function GetAllUsers() As List(Of User)
Dim userList = New List(Of User)
Try
Using mMysqlconnection = New MySqlConnection("server='192.168.100.2'; database='mydb';Port=3306; UID='epb'; password='hahaha'; pooling=true")
mMysqlconnection.Open()
Using command = New MySqlCommand("SELECT * FROM USER ORDER By UserName", mMysqlconnection)
Using rdr = command.ExecuteReader()
While rdr.Read()
Dim user = New User()
user.UserName = rdr.GetString(0)
userList.Add(user)
End While
End Using
End Using
End Using
Catch exceptionThatICaught As System.Exception
MessageBox.Show("meaningful message here, logging would be useful too")
Return Nothing
End Try
Return userList
End Function
Maybe helpful because related(you're also reusing the connection): ExecuteReader requires an open and available Connection. The connection's current state is Connecting
It will be something like this.
Public Function OpenMysqlCon() As MySqlConnection
Dim mMysqlconnection As MySqlConnection()
Try
Dim strconDB As String = "server='192.168.100.2'; database='mydb';Port=3306; UID='epb'; password='hahaha'; pooling=true"
mMysqlconnection = New MySqlConnection
mMysqlconnection.ConnectionString = strconDB
mMysqlconnection.Open()
Catch exceptionThatICaught As System.Exception
mMysqlconnection = Nothing
End Try
Return mMysqlconnection
End Function
Private Sub frmTest_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim con As MySqlConnection = OpenMysqlCon
If con Is Nothing Then
MessageBox.Show("connection not available at the moment, please try again later")
'Me.Close 'uncomment if the app should end
End If
End Sub
edit - this is not tested
Using con As MySqlConnection = OpenMysqlCon
If con Is Nothing Then
MessageBox.Show("connection not available at the moment, please try again later")
'Me.Close 'uncomment if the app should end
Else
'your code
End If
End Using

Accessing "all" declared variables in Class1.vb to many forms of a solution in vb.net

After a series of downloading connectors && some plugins, I finally managed to connect xampp to VB.Net. Though I found it very time-consuming/hassle everytime I put a connection string to each form that requires SQL insert and select statements So I came up with the idea of creating a Class1.vb and place there all the connection strings to xampp. So that everytime I created I new form, all I have to do is to import Class1.vb to each form so I could access the Dim conn As New MySqlConnection which as I have mentioned is declared on Class1.vb
Though, somehow I get connected with MYSQL most of the variables including one that bears the name of the dbtable cannot be access.
Let me show you what's inside my Class1.vb
Public Class Class1
Dim conn As New MySqlConnection
Dim command As MySqlCommand
Dim reader As MySqlDataReader
Public Sub mysqlConnect()
If Not conn Is Nothing Then conn.Close()
conn.ConnectionString = String.Format('connectionString for Dbname,server,uid,pword)
Try
conn.Open()
MessageBox.Show("Connected!")
Catch x As Exception
MsgBox(x.Message)
End Try
conn.Close()
end sub
end class
Inside Form1.vb
Public Class Form1
Dim newCon as New Class1
Private Sub Form2_Load
newCon.mysqlConnect()
'Note: mysqlConnect() is a function declared in Class1.vb
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Try
conn.Open()
Catch x As Exception
End Try
Dim command As New MySqlCommand(String.Format("INSERT STATEMENT"))
command.ExecuteNonQuery()
conn.Close()
End Sub
But the variables I indicate on Button1_Click aren't working. It's as if it cannot read some functions of the Public Sub Connect()
Though, as I have mentioned earlier, the Msgbox("Connected") did work which means that I am totally connected with my DB.
Any ideas, my friends?
Your comments are appreciated. Thanks in advance.
Two common solutions are:
1) Change your Class1 to have a "Factory method" which will give you an open connection.
2) Wrap your connection inside of your class
Example 1:
Public Class Class1
Dim conn As New MySqlConnection
Dim command As MySqlCommand
Dim reader As MySqlDataReader
Public Shared Function mysqlConnect() AS MySqlConnection
If Not conn Is Nothing Then conn.Close()
conn.ConnectionString = String.Format('connectionString for Dbname,server,uid,pword')
Try
conn.Open()
''MessageBox.Show("Connected!")
Catch x As Exception
MsgBox(x.Message)
End Try
''conn.Close() ''This must be done by your calling function now
''btw, if you forget, it may cause connection leaks, which are evil
Return conn
End function
End class
Example 2:
Public Class Class1
Public conn As MySqlConnection
Dim command As MySqlCommand
Dim reader As MySqlDataReader
''open the connection in the constructor
Sub New()
conn = New MySqlConnection
conn.ConnectionString = String.Format('connectionString for Dbname,server,uid,pword')
Try
conn.Open()
''MessageBox.Show("Connected!")
Catch x As Exception
MsgBox(x.Message)
End Try
End Sub
''close the connection in the destructor
Protected Overrides Sub Finalize()
conn.Close() ''automatically runs when this class is garbage collected
conn.Dispose()
End Sub
End class

.NET - Importing class with connection to database

I want to import a class to another class so that I don't have to write the same code X times.
I have a file with the connection to the database called connectDB.vb.
Imports MySql.Data.MySqlClient
Namespace connectDB1
Public Class connectDB
Dim connection As New MySqlConnection("Server=localhost; UserId=root;
Password=root; Database=something")
Public Sub doConnection()
Try
connection.Open()
Catch ex As Exception
MsgBox("Error")
End Try
End Sub
End Class
End Namespace
And I want to import connectDB.vb to File1.vb
Imports MySql.Data.MySqlClient
Imports MyApp.connectDB1
Public Class File1
Dim connectDataBase As New connectDB
Dim connection As New MySqlConnection("Server=localhost; UserId=root; Password=root; Database=something")
Private Sub File1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
'doConnection()
connectDataBase.doConnexion()
End Sub
'Private Sub doConnection()
' Try
' connection.Open()
' Catch ex As Exception
' MsgBox("Error")
' End Try
'End Sub
Private Sub addProduct()
Dim dbcomm As MySqlCommand
Dim dbread As MySqlDataReader
If txtBoxQuantity.Text <> "" And txtBoxPrice.Text <> "" And txtBoxProduct.Text <> "" Then
dbcomm = New MySqlCommand("insert into products (price, stock, name) values(#price, #stock, #name)", connection)
dbcomm.Parameters.AddWithValue("#price", txtBoxPrice.Text())
dbcomm.Parameters.AddWithValue("#stock", txtBoxQuantity.Text())
dbcomm.Parameters.AddWithValue("#name", txtBoxProduct.Text())
dbread = dbcomm.ExecuteReader() ' GIVES ERROR
dbread.Close()
End If
End Sub
Private Sub add_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles agregarProducto.Click
addProduct()
End Sub
End Class
But when I run this code that it's suposed to save the data in the DB it gives me this error:
InvalidOperationException was unhandled. Connection must be valid and open.
connectDB.vb connects to the database since I debugged and it connects to the DB, but when I want to do some sql sentence in the File1.vb it gives that error.
Without trying to import the class the code works, but I'm just trying to improve my code, as you can see the commented code is the code I used to connect to the database.
Try adding this
Public Sub New()
connectDataBase = New connectDB()
connection = New MySqlConnection("Server=localhost; UserId=root; Password=root; Database=something")
End Sub

VB.NET application unable to run on other computer

I can debug my project with no errors, but when I build it and copy the executable application to another computer, the application is not running at all. The form does not even appear on screen.
(Here) is the screenshot of my error.
Here is my source code.
Imports System.Data.SqlClient
Imports MySql.Data.MySqlClient
Public Class Form1
Dim MySQLConnection = New MySqlConnection
Dim Command As New MySqlCommand
Dim MyAdapter As New MySqlDataAdapter
Dim sqlCommand As New MySqlCommand
Dim str_carSql As String
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim response As Boolean = False
Button1.Enabled = False
Try
response = My.Computer.Network.Ping("www.db4free.net")
Label2.Text = "ONLINE"
Label2.ForeColor = Color.Green
Button1.Enabled = True
Catch ex As Exception
Label2.Text = "OFFLINE"
Label2.ForeColor = Color.Red
MsgBox("No internet connection!", MsgBoxStyle.Critical)
End Try
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Me.Cursor = Cursors.WaitCursor
Try
MySQLConnection.ConnectionString = "server=db4free.net ;port=3306; user=prav5ef; password=prav5eF; database=databasetest;"
MySQLConnection.Open()
MsgBox("Connected to server!")
Catch ex As Exception
MsgBox("Failed connecting to server!", MsgBoxStyle.Critical)
End Try
Try
str_carSql = "insert into databasetest (id,name,password) values (#id,#name,#password)"
sqlCommand.Connection = MySQLConnection
sqlCommand.CommandText = str_carSql
sqlCommand.Parameters.AddWithValue("#id", TextBox1.Text)
sqlCommand.Parameters.AddWithValue("#name", TextBox2.Text)
sqlCommand.Parameters.AddWithValue("#password", TextBox3.Text)
sqlCommand.ExecuteNonQuery()
Catch ex As Exception
MsgBox("ID existed: Could not insert record")
End Try
MsgBox("Done")
Application.Restart()
End Sub
End Class
Here is how the application suppose to show :
And the online database that I am using is db4free.net :
Since you did not provide enough information on the error, these are the following problems you might be experiencing, and the solutions to said problems:
A.) Your client may not be running the correct .NET framework for your Program. In which case, install the correct .NET Framework by downloading it here.
B.) You did not include the mysl.data.dll on the client unit. In which case, download the .dll from here and install it in the client unit.

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.