Close connection after calling ExcuteScalar - sql

i have the following function, the problem is since im using ExecuteScalar, the connection never closes when using any other function again...
Public Function Valor(tabla As String, campos As String, condicion As String)
cn.Open()
Dim sql As String = "SELECT " & campos & " FROM " & tabla & " WHERE " & condicion
comando = New SqlCommand(sql, cn)
Return comando.ExecuteScalar
If cn.State = ConnectionState.Open Then
cn.Close()
End If
End Function
This Function returns me a Time value from SQL time(7) to TIMESPAN on the app, i am able to get the value but Since Return skips anything after it, connection is not closed.
ANy idea how to close the connection this?
or there is another method on how can i get the value of my query.
Thanks in advance

First of all, connections in .Net work best when you create an entirely new object for each query. Don't try to re-use the same connection all the time.
Second, that code could still leak connections even if you had closed the connection before returning, because it would never reach .Close() function call if an exception is thrown.
Finally, that code is horribly vulnerable to sql injection. It's practically begging to get hacked.
Here is code that solves all three problems:
Public Function Valor(ByVal sql As String, ByVal ParamArray condicion() As SqlParameter)
'cnString is a made-up string variable for the connection string that you will create in the same place (and instead of) that you currently have cn
Using cn As New SqlConnection(cnString), _
cmd As New SqlCommand(sql, cn)
If condicion IsNot Nothing Then cmd.Parameters.AddRange(condicion)
cn.Open()
Return cmd.ExecuteScalar()
End Using
End Function

Instead of returning immediately, store the result in a variable, clean up everything, then return the cached variable:
Public Function Valor(tabla As String, campos As String, condicion As String)
cn.Open()
Dim sql As String = "SELECT " & campos & " FROM " & tabla & " WHERE " & condicion
comando = New SqlCommand(sql, cn)
Dim retorno As Object = comando.ExecuteScalar()
If cn.State = ConnectionState.Open Then
cn.Close()
End If
Return retorno
End Function

Related

How to concatenate single quote in MySQL query with VB.NET parameter?

I am making a MySQL Select query using MySQLCommand object in VB.NET were I use parameters. I am facing an issue, in my where clause, I need to put the value for the criteria into single quote, I tried to use backslash ' (\') to escape the single quote, it does not work. I used double quotes as well, same issue. Can somebody help me? Is there something specific I need to do when using the MySQLCommand object in VB.NET with parameter and want my parameter value to be in single quote into a query?
Here is the Function in which I make the MySQL query:
Public Shared Function getGeographyUnits(critere As String, valeur As String) As List(Of geography_unit)
Dim conn As MySqlConnection = DBUtils.GetDBConnection()
Dim rdr As MySqlDataReader
conn.Open()
Dim cmd As MySqlCommand = New MySqlCommand("select ID,description from geography_unit where #critere = ''#valeur''", conn)
cmd.Parameters.AddWithValue("#critere", critere)
cmd.Parameters.AddWithValue("#valeur", valeur)
rdr = cmd.ExecuteReader()
Dim geography_units As New List(Of geography_unit)
While rdr.Read
Dim geography_unit As New geography_unit
Try
geography_unit.ID = CLng(rdr("Id"))
geography_unit.description = rdr("description")
Catch ex As Exception
End Try
geography_units.Add(geography_unit)
End While
rdr.Close()
conn.Close()
Return geography_units
End Function
Actually, I want the cmdText for my query to be something like this after rendering:
select ID,description from geography_unit where critere = 'valeur'
The issue comes mainly from the fact that I am using parameter, how can I solve it?
You need to fix your code with something like this. But please note a couple of things.
If the #valeur is enclosed in single quotes it is no more a parameter placeholder but a string constant and the parameter associated with the placeholder will not be used.
The connection should always enclosed in a using statement to avoid dangerous resources consuption on the server
If you want to have a variable list of field to which apply the valeur passed then you need to be absolutely sure that your user is not allowed to type the value for critere. You should provide some kind of control like combobox or dropdwonlist where the user could only choose between a prefixed set of values, then you can concatenate the critere variable to your sql command.
Public Shared Function getGeographyUnits(critere As String, valeur As String) As List(Of geography_unit)
Using conn As MySqlConnection = DBUtils.GetDBConnection()
Dim sqlText As String = "select ID,description from geography_unit"
conn.Open()
If Not String.IsNullOrEmpty(critere) Then
sqlText = sqlText & " where " & critere & " = #valeur"
End If
Dim cmd As MySqlCommand = New MySqlCommand(sqlText, conn)
cmd.Parameters.Add("#valeur", MySqlDbType.VarChar).Value = valeur
Using rdr As MySqlDataReader = cmd.ExecuteReader()
Dim geography_units As New List(Of geography_unit)
While rdr.Read
Dim geography_unit As New geography_unit
Try
geography_unit.ID = CLng(rdr("Id"))
geography_unit.description = rdr("description")
Catch ex As Exception
End Try
geography_units.Add(geography_unit)
End While
End Using
' rdr.Close() not needed when inside using
' conn.Close() not needed when inside using
Return geography_units
End Using
End Function
Also worth of note is the point in which I have used the Add method to add the parameter to the collection. The AddWithValue, while convenient, is the cause of a lot of bugs because it defines the type of the parameter looking at the argument received. This could end very badly when you pass dates or decimal numbers directly from a string.
Quite simply, as valeur is a string then your query needs to be as follows
"select ID,description from geography_unit where critere = '" & valeur & "'"
If valeur was numeric then the format should be as follows
"select ID,description from geography_unit where critere = " & valeur
Note the difference where single quotes are included within double quotes around the variable when it is a string.

Having the ExecuteNonQuery : connection property has not been initialized

I'm trying to delete an entry from my database. But when the ExecuteNonQuery has to do it's job it can't find the enabled connection and give me this error :
System.InvalidOperationException :'ExecuteNonQuery : connection property has not been initialized'
Here is what I did :
Dim delete As New OleDbCommand
Dim da As OleDbDataAdapter
Dim ds As DataSet
Dim dt As DataTable
initConnectionDtb(pathDtb)
openConnection()
If TextBox2.Text <> "" Then
delete.CommandText = "delete FROM USERS WHERE NAME = '" & TextBox2.Text & "'"
delete.CommandType = CommandType.Text
delete.ExecuteNonQuery()
MsgBox("USER HAS BEEN DELETED")
Else
MsgBox("ERROR")
End If
I could check if it was properly connected to the Database thanks to connectionName.State
I also enterily rewrote the connetion to the database in the function but ExecuteNonQuery still couldn't connect even though the connection was opened
I saw that i'm not the only one on this website but none of the previous answers have helped me.
#Filburt pointed out, how are you assigning your connection to your command object. Here is an example :
Using connection As OleDbConnection = New OleDbConnection(connectionString)
connection.Open()
Dim command As OleDbCommand = New OleDbCommand(queryString, connection)
command.ExecuteNonQuery()
End Using
In your code, you need to assign the connection object to your command object. We can't see what code you have in initConnectionDtb(pathDtb) or openConnection()
To adapt this to your code:
delete.Connection = <<your connection object here>>
delete.CommandText = "delete FROM USERS WHERE NAME = '" & TextBox2.Text & "'"
delete.CommandType = CommandType.Text
delete.ExecuteNonQuery()
Another note: look into parameterizing your query strings instead of hand stringing the values. This will prevent issues with TextBox2.Text having a value like O'Toole which will cause a syntax error as well as SQL Injection.
Here's what i used to initialize my connection :
Public Function initConnectionDtb(ByVal path As String) As Boolean
initConnectionDtb = True
Connection = New OleDbConnection
Try
Connection.ConnectionString = "provider=microsoft.jet.oledb.4.0;" & "data source= " & path & ";"
Catch ex As Exception
Return False
End Try
End Function
Public Function openConnection() As Boolean
openConnection = True
Try
Connection.Open()
MsgBox(Connection.State) 'to test if my connection really openned in my previous post
Catch ex As Exception
MsgBox(ex.Message)
Return False
End Try
End Function
Public Sub closeConnection()
If Not IsNothing(Connection) Then
If Connection.State = ConnectionState.Open Then
Connection.Close()
End If
MsgBox(Connection.State)
Connection.Dispose()
Connection = Nothing
End If
End Sub
So far it worked for everything i tried (adding someone to the database for exemple)

Converting VBA function to VB.net to get sql data

I am trying to convert VBA code into VB.net and I have made it to a point but I can't convert resultset into vb.net. RS was 'dim as resultset' in VBA, thought i could just change it to dataset but am getting errors with the '.fields' and other options?
Function GetG(sDB As String, sServ As String, sJob As String) As String
'sDB = Database name, sServ = Server\Instance, path = job.path
Dim conString As String = ("driver={SQL Server};server = " &
TextBox1.Text & " ; uid = username;pwd=password:database = " &
TextBox2.Text)
Dim RS As DataSet
Dim conn As SqlConnection = New SqlConnection(conString)
Dim cmd As SqlCommand
conn.Open()
'This is where my problems are occuring
cmd = New SqlCommand("SELECT [ID],[Name] FROM dbo.PropertyTypes")
Do While Not RS.Tables(0).Rows.Count = 0
If RS.Fields(1).Value = sJob Then
GetG = RS.Fields(0).Value
GetG = Mid(GetG, 2, 36)
Exit Do
End If
DataSet.MoveNext
Loop
conn.Close
End Function
Based on my understanding and some guesswork, here is what I came up with for what I think you're wanting.
As I stated in my comment above, it appears you can just use a WHERE clause to get the exact record you want (assuming a single instance of sJob appears in the name column).
Build the connectionstring off the input arguments, not controls on your form. That is after all why you allow for arguments to be passed along. Also note that there is a SqlCommandBuilder object that may be of interest. But for now
Function GetG(sDB As String, sServ As String, sJob As String) As String
'we'll pretend your connectionstring is correct based off of the sDB and sServ arguments
Dim conStr As String = ("driver={SQL Server};server = " & sServ & " ; uid = username;pwd=password:database = " & sDB)
'Create a connection and pass it your conStr
Using con As New SqlConnection(conStr)
con.Open() 'open the connection
'create your sql statement and add the WHERE clause with a parameter for the input argument 'sJob'
Dim sql As String = "SELECT [ID], [Name] FROM dbo.PropertyTypes WHERE [Name] = #job"
'create the sqlCommand (cmd) and pass it your sql statement and connection
Using cmd As New SqlCommand(sql, con)
'add a parameter so the command knows what #job holds
cmd.Parameters.Add(New SqlParameter("#job", SqlDbType.VarChar)).Value = sJob
'Now that have the command built, we can pass it to a reader object
Using rdr As SqlDataReader = cmd.ExecuteReader
rdr.Read()
'i admin i'm a little confused here on what you are
'trying to achieve so ID may not be what you are
'really wanting to get a substring of.
Return rdr("ID").ToString.Substring(2, 36)
End Using
End Using
End Using
End Function
An example to see if this is working could be to call a messagebox do display the result. For this example, I'm going to pretend that TextBox3 holds the sJob you're wanting. With that knowledge, you could simply do:
MessageBox.Show(GetG(TextBox2.Text, TextBox1.Text, TextBox3.Text))
This should then produce the result in a messagebox.
It seems that you're not filling your DataSet. So, when you try to loop through it, it's uninitialized or empty.
Check this answer to see an example: Get Dataset from DataBase

VB.NET WCF - Error Using my function

I have a function to get information on a SQL Server Table. I know the function is correct and returning everything as suposed too (I used msgBox to check it). The problem is when I try to use that function it displays an error:
My WCF Function:
Public Function GetCLInfo(ByVal cl_ID As Integer) Implements SQLOperator.GetCLInfo
Dim CLInfo(7) As String
Try
SQLCon.ConnectionString = SQLConString
SQLCon.Open()
SQLCMD = New SqlCommand("Select * from dbo.cl Where ID=" & cl_ID & ";", SQLCon)
SQLDataReader = SQLCMD.ExecuteReader()
While SQLDataReader.Read
CLInfo(0) = SQLDataReader("ID")
CLInfo(1) = SQLDataReader("Name")
CLInfo(2) = SQLDataReader("Address")
CLInfo(3) = SQLDataReader("Contact")
End While
Return CLInfo
Catch ex As Exception
MsgBox("Error: " & Environment.NewLine & ex.ToString)
CLInfo(0) = "False"
Return CLInfo
Finally
SQLCon.Close()
SQLCon.Dispose()
End Try
Return CLInfo
End Function
In the picture you can see aswell how I'm trying to use the function.
Can someone kindly tell me what am I doing wrong?
Your problem is that you are calling a function to return string array and program doesn't catch by itself. As #Matt Wilko point out use Option Strict On.
Second if you have more than one client your logic fails.
For I as integer = 1 to AllCl
Dim cl(7) as String
cl = Service.GetClInfo(I)
next
Above code will reset every each time, plus when you leave for loop you are loosing access to cl.
Ugly fix could be multidimensional array.
Now you should specify your return type
Public Function GetCLInfo(ByVal cl_ID As Integer) As String() Implements SQLOperator.GetCLInfo

Inserting variables into a query string - it won't work!

Basically i have a query string that when i hardcode in the catalogue value its fine. when I try adding it via a variable it just doesn't pick it up.
This works:
Dim WaspConnection As New SqlConnection("Data Source=JURA;Initial Catalog=WaspTrackAsset_NROI;User id=" & ConfigurationManager.AppSettings("WASPDBUserName") & ";Password='" & ConfigurationManager.AppSettings("WASPDBPassword").ToString & "';")
This doesn't:
Public Sub GetWASPAcr()
connection.Open()
Dim dt As New DataTable()
Dim username As String = HttpContext.Current.User.Identity.Name
Dim sqlCmd As New SqlCommand("SELECT WASPDatabase FROM dbo.aspnet_Users WHERE UserName = '" & username & "'", connection)
Dim sqlDa As New SqlDataAdapter(sqlCmd)
sqlDa.Fill(dt)
If dt.Rows.Count > 0 Then
For i As Integer = 0 To dt.Rows.Count - 1
If dt.Rows(i)("WASPDatabase") Is DBNull.Value Then
WASP = ""
Else
WASP = "WaspTrackAsset_" + dt.Rows(i)("WASPDatabase")
End If
Next
End If
connection.Close()
End Sub
Dim WaspConnection As New SqlConnection("Data Source=JURA;Initial Catalog=" & WASP & ";User id=" & ConfigurationManager.AppSettings("WASPDBUserName") & ";Password='" & ConfigurationManager.AppSettings("WASPDBPassword").ToString & "';")
When I debug the catalog is empty in the query string but the WASP variable holds the value "WaspTrackAsset_NROI"
Any idea's why?
Cheers,
jonesy
alt text http://www.freeimagehosting.net/uploads/ba8edc26a1.png
I can see a few problems.
You are using concatenation in a SQL statement. This is a bad practice. Use a parameterized query instead.
You are surrounding the password with single quotes. They are not needed and in fact, I'm surprised it even works assuming the password itself does not have single quotes.
You should surround classes that implement IDisposable with a Using block
You should recreate the WASP connection object in GetWASPcr like so:
Public Sub GetWASPAcr()
Dim username As String = HttpContext.Current.User.Identity.Name
Dim listOfDatabaseConnectionString As String = "..."
Using listOfDatabaseConnection As SqlConnection( listOfDatabaseConnectionString )
Using cmd As New SqlCommand("SELECT WASPDatabase FROM dbo.aspnet_Users WHERE UserName = #Username")
cmd.Parameters.AddWithValue( "#Username", username )
Dim dt As New DataTable()
Using da As New SqlDataAdapter( cmd )
da.Fill( dt )
If dt.Rows.Count = 0 Then
WaspConnection = Null
Else
Dim connString As String = String.Format("Data Source=JURA;Initial Catalog={0};User Id={1};Password={2};" _
, dt.Rows(0)("WASPDatabase") _
, ConfigurationManager.AppSettings("WASPDBUserName") _
, ConfigurationManager.AppSettings("WASPDBPassword"))
WaspConnection = New SqlConnection(connString);
End If
End Using
End Using
End Using
End Sub
In this example, listOfDatabaseConnectionString is the initial connection string to the central database where it can find the catalog name that should be used for subsequent connections.
All that said, why would you need a class level variable to hold a connection? You should make all your database calls open a connection, do a sql statement, close the connection. So, five database calls would open and close a connection five times. This sounds expensive except that .NET gives you connection pooling so when you finish with a connection and another is requested to be opened, it will pull it from the pool.
Your string passed into the constructor for this SqlConnection object will be evaluated when the class is instantiated. Your WASP variable (I'm assuming) won't be set until the method you have shown is called.
Might want to quit looking one you have found your database:
For i As Integer = 0 To dt.Rows.Count - 1
If dt.Rows(i)("WASPDatabase") Is DBNull.Value Then
WASP = ""
Else
WASP = "WaspTrackAsset_" + dt.Rows(i)("WASPDatabase")
break
End If
Next
[link text][1]You are building your string on the fly by adding the value of a column to a string. So, for the row in question for the column "WASPDatabase" was tacked on to your string. So you got what it had. On another note, your earlier query of "select ... from ... where ..." where you are manually concatinating the string of a variable makes you WIDE OPEN to SQL-Injection attacks.
Although this link [1]: how to update a table using oledb parameters? "Sample query using parameterization" is to a C# sample of querying with parameterized values, the similar principles apply to most all SQL databases.
At the time you're creating the new connection, WASP is holding the value you want it to be holding? It is a string data type? Try adding .ToString after WASP and see if that helps anything.
Interesting problem. =-)
The problem is, as Paddy already points out, that the WaspConnection object gets initialized before you even have the chance to call GetWASPAcr. Try this:
Public Sub GetWASPAcr()
'[...]
End Sub
Dim _waspConnection As SqlConnection
Public Readonly Property WaspConnection As SqlConnection
Get
If _waspConnection Is Nothing Then
GetWASPAcr()
_waspConnection = New SqlConnection("Data Source=JURA;Initial Catalog=" & WASP & ";User id=" & ConfigurationManager.AppSettings("WASPDBUserName") & ";Password='" & ConfigurationManager.AppSettings("WASPDBPassword").ToString & "';")
End If
Return _waspConnection
End Get
End Property