Currently I'm trying to understand and learn new code commands for vb.net. i have came across three codes while researching which is
"SELECT staff_id,pass_word FROM userlogin WHERE staff_id = #staff_id AND pass_word = #pass_word")
Second code:
Dim uName As New OleDbParameter("#staff_id", SqlDbType.VarChar)
Third and last:
uName.Value = txtstaffid.Text
myCommand.Parameters.Add(uName)
What are the uses of #pass_word code when you have already typed the pass_word column, Oledbparameter, and Parameters.Add?
The following code shows a bit more complete picture of what the code is doing. The Using...End Using blocks ensure that your objects are closed and disposed even if there are errors. Of course, in a real application, passwords would never be stored as plain text (too easy to hack). They would be salted and hashed but that is for another day.
Private Sub CheckPassword()
'This line assigns a Transact SQL command to a string variable.
'It will return a record with 2 columns. The #staff_id and #pass_word are parameter placeholders.
'The use of parameters limits the possibilit of SQL injection with malicious input be the user
'typing in the text box.
Dim strSQL = "SELECT staff_id,pass_word FROM userlogin WHERE staff_id = #staff_id AND pass_word = #pass_word;"
Using cn As New SqlConnection("Your connection string")
'Pass the command string and the connection to the constructor of the command.
Using cmd As New SqlCommand(strSQL, cn)
'It is unneccessary to create a command variable.
'The .Add method of the commands Parameters collection will create a parameter.
cmd.Parameters.Add("#staff_id", SqlDbType.VarChar).Value = txtstaffid.Text
cmd.Parameters.Add("#pass_word", SqlDbType.VarChar).Value = txtPassword.Text
cn.Open()
Using dr As SqlDataReader = cmd.ExecuteReader
'All we really need to know is whether we returned a row.
If dr.HasRows Then
MessageBox.Show("Login Successful")
Else
MessageBox.Show("Login Failed")
End If
End Using
End Using
End Using
End Sub
Related
Can someone please explain to me when the "size" column wont work for comparison but I can replace the ID column in my code and it works perfectly fine. Perhaps my formatting of the access database column for Size isnt correct?
I am basically just trying to see if the key and value in my dictionary match the conditions in the access database and if so to write one text, if not write another. The error I keep getting when I have size in my code is:
An unhandled exception of type 'System.Data.OleDb.OleDbException' occurred in System.Data.dll IErrorInfo.GetDescription failed with E_FAIL(0x80004005).
For Each KeyPair In dict
Dim key As String
Dim value As Integer
key = KeyPair.Key
value = KeyPair.Value
Dim sqlQry As String
sqlQry = "SELECT Item, Size FROM [Table] WHERE Item = '" & key & "'AND Size>" & value & " "
Console.WriteLine(sqlQry)
Dim topDecision As String
Dim cmd As OleDbCommand
cmd = New OleDbCommand(sqlQry, myconnection)
Dim myreader As OleDbDataReader
myreader = cmd.ExecuteReader()
If myreader.Read() Then
topDecision = "Order"
Else
topDecision = "Dont"
End If
myreader.Close()
Next
Connections and some other database objects provided by ADO.net use unmanaged code internally. They provide a .Dispose method where they release these resources. It is up to the coder to call the .Dispose method. Fortunately, .net provides Using...End Using blocks that handle this for us. Connections, commands and readers should be declared in the method where they are used so they can be properly closed and disposed.
Don't concatenate strings to build sql queries. Use parameters to avoid sql injection. We only need a single command and a single ParametersCollection. Only the values of the parameters change inside the loop.
A special note for OleDb parameters. The names of the parameters are ignored. The position of the parameter in the sql query should match the order that they are added to the ParametersCollection.
Declare KeyPair As KeyValuePair so you can access .Key and .Value properties.
I used a StringBuilder to collect the messages from your code. A StringBuilder is mutable (changeable) whereas a String is not. If I used a String the compiler would have to throw away a string and create a new one on each iteration. The garbage collector would be kept busy.
I used an interpolated string indicated by the $ before the string. It allows us to insert variables directly into the string if they are surrounded by braces { }.
If you follow this sample, be sure the text box at the end has Multiline = True.
Private Sub OPCode()
Dim sqlQry = "SELECT Item, Size FROM [Table] WHERE Item = #Key AND Size > #Value;"
Dim sb As New StringBuilder
Using cn As New OleDbConnection("Your connection string"),
cmd As New OleDbCommand(sqlQry, cn)
cmd.Parameters.Add("#Key", OleDbType.VarChar, 100)
cmd.Parameters.Add("#Value", OleDbType.Integer)
cn.Open()
For Each KeyPair As KeyValuePair(Of String, Integer) In dict
cmd.Parameters("#Key").Value = KeyPair.Key
cmd.Parameters("#Value").Value = KeyPair.Value
Dim topDecision As String
Using myreader = cmd.ExecuteReader()
If myreader.Read() Then
topDecision = "Order"
Else
topDecision = "Dont Order"
End If
End Using
sb.AppendLine($"{KeyPair.Key} - {topDecision}")
Next
End Using
TextBox1.Text = sb.ToString
End Sub
This is my Code and it just doesn't work, I'm trying to make it Delete a record where the column staffID is equal to the variable currentStaffID although it doesn't delete the record or give an error, it just carries on and displays the MsgBox after the DELETE Statement.
Dim AreYouSureEdit = MsgBox("Are you sure you want to delete this record?", MsgBoxStyle.YesNo)
If DbConnect() And AreYouSureEdit = MsgBoxResult.Yes Then
Dim SQLCmd As New OleDbCommand
SQLCmd.Connection = cn
currentStaffID = editStaffIDTxtBox.Text()
SQLCmd.CommandText = "DELETE * STAFF WHERE staffID = #currentStaffID"
cn.Close()
MsgBox("Record Deleted.", MsgBoxStyle.OkOnly)
End If
You're setting up your command and everything - but you're never executing it! Of course nothing happens.....
You need to add one line of code:
Dim SQLCmd As New OleDbCommand
SQLCmd.Connection = cn
currentStaffID = editStaffIDTxtBox.Text()
SQLCmd.CommandText = "DELETE * STAFF WHERE staffID = ?"
'' You need to define the parameter and set its value here!
SQLCmd.Parameters.Add("p1", OleDbType.Int).Value = currentStaffID;
'' you need to actually **EXECUTE** your DELETE query!
SQLCmd.ExecuteNonQuery()
cn.Close()
Also, while you're setting up a parameter in your SQL query text just fine, I don't see where you're actually defining such a parameter on your SQLCmd object - and also be aware: OleDB doesn't use named parameters (like the native SQL Server client does) - it uses positional parameters (so that's what I replaced your named parameter with just a ?). Since there's only one parameter, this shouldn't be a problem here - but you need to properly define the SQLCmd's parameter (and set its value)
Connections and Commands can use unmanaged resources so, they need to have their .Dipose methods called to release these resources. Using...End Using blocks take care of this and also .Close the connection. Your database objects must be local to the method where they are used for this to work.
Always use Parameters to avoid Sql injection.
Private Sub OpCode()
Dim AreYouSureEdit = MsgBox("Are you sure you want to delete this record?", MsgBoxStyle.YesNo)
If AreYouSureEdit = MsgBoxResult.Yes Then
Using cn As New OleDbConnection("Your connection string"),
SQLCmd As New OleDbCommand("DELETE From STAFF WHERE staffID = #currentStaffID", cn)
SQLCmd.Parameters.Add("#currentStaffID", OleDbType.Integer).Value = CInt(editStaffIDTxtBox.Text)
cn.Open()
SQLCmd.ExecuteNonQuery()
End Using
MsgBox("Record Deleted.", MsgBoxStyle.OkOnly)
End If
End Sub
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.
I want to use multiple connection in if else code block but it's giving the following error when I checked in a Messagebox :
"Argument prompt cannot be converted to string"
Here is my code :
Try
Conn.Open()
Com.CommandText = "Select * FROM Table1 WHERE ID=" & txtID.Text & " AND DOR=#01/01/1900# AND Paid = '0' ORDER BY DOI"
Dr = Com.ExecuteReader
If Dr.Read = True Then
txtInstNo.Text = Dr(2)
txtInstAmount.Text = Dr(4)
Else
If MsgBox("Wait! You're not allowed to do it. Do you still want to continue ? ", MsgBoxStyle.YesNo Or MsgBoxStyle.Question, "Alert") = MsgBoxResult.Yes Then
Try
Dim Con As New OleDbConnection
Dim Comm As New OleDbCommand
Dim Dr2 As OleDbDataReader
Con.ConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=|DataDirectory|\Database.accdb"
Con.Open()
Comm.Connection = Con
Comm.CommandText = "Select * FROM Table1 WHERE ID=" & txtID.Text & " AND DOR=#01/01/1900# AND Paid = '0' ORDER BY DOI"
Comm.CommandType = CommandType.Text
Dr2 = Comm.ExecuteReader
MsgBox(Dr2) <-- Here I got that error
If Dr.Read = True Then
txtInstNo.Text = Dr(2)
txtInstAmount.Text = Dr(4)
Else
MsgBox("Sorry, no record found",MsgBoxStyle.Exclamation, "Alert")
End If
Dr2.Close()
Con.Close()
Catch ex As Exception
MsgBox(ex.Message)
End Try
End If
End If
Dr.Close()
Conn.Close()
Catch ex As Exception
MsgBox(ex.Message)
End Try
Your query might be returning entire rows, objects, widgets or whatever. As #Andrew Morton pointed out, it's a Data Reader. It's not going to implicitly convert your result. You'll have to manipulate your reader result and convert it to a string to do anything useful. You'll also have to handle if your DataReader returns a null result, which when converted should be "" an empty string.
If you just want to see what Dr2 contains, you could try MsgBox(CStr(Dr2)). No error handling, if it throws an exception.
There are a few things which could be modified in your code to make it a bit shorter and so easier to track down what is not working. It is easier to isolate a problem if you have the minimal amount of code which shows the problem: How to create a Minimal, Complete, and Verifiable example.
I'll show my suggestion for a minimal amount of code on a new form which should help you narrow down where the problem is, and then I'll go over why I have written it that way and what could be going wrong.
Option Strict On
Option Infer On
Imports System.Data.OleDb
Public Class Form1
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim connStr = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=|DataDirectory|\Database.accdb"
Dim sql = "SELECT InstNo, InstAmount FROM Table1 WHERE ID = ? AND DOR = #01/01/1900# AND PAID='0' ORDER BY DOI"
' lists to hold the retrieved data
Dim instNos As New List(Of String)
Dim instAmounts As New List(Of String)
' get the data
Using conn As New OleDbConnection(connStr)
Using cmd As New OleDbCommand(sql, conn)
cmd.Parameters.Add(New OleDbParameter With {.ParameterName = "#ID",
.DbType = DbType.String,
.Value = txtID.Text})
conn.Open()
Dim rdr = cmd.ExecuteReader()
While rdr.Read
instNos.Add(rdr.GetString(0))
instAmounts.Add(rdr.GetString(1))
End While
End Using
End Using
' act on the data
If instNos.Count = 0 Then
MsgBox(String.Format("No records were found for ID ""{0}"".", txtID.Text))
Else
txtInstNo.Text = String.Join(vbCrLf, instNos)
txtInstAmount.Text = String.Join(vbCrLf, instAmounts)
End If
End Sub
End Class
The code.
I start with Option Strict On to make sure that all data types match up and I haven't done anything else silly which Visual Studio can point out to me.
I use Option Infer On so that I don't have to type out the type of variables when the compiler can infer what they are.
I used just one Button on the form along with the three named textboxes as we are going for minimal code.
I set up the two strings which are going to be used in one place at the top of the sub because it is easier to maintain the code that way. Normally, you would declare variables just before they are used to minimise their scope.
I specified exactly which columns I want from the database. There is no point retrieving all of them with *. I had to guess what the columns are called - you will need to put in the actual names if they are different.
The result of a query to the database might have more than one record, so I initialise Lists for the data. (Your query has an ORDER BY so I assume that there could be more than one record.)
The Using statement makes sure that resources are released cleanly whatever else happens.
For OleDb, parameters are normally represented by a ?. (If there is more than one, they are all represented by question marks and the parameters must be added in the order in which they are to be put into the query.) I had to guess at the data type for the ID column - please put in the correct type. When you create the parameter, you can still use a meaningful name for it, even though it is ignored by the computer.
Next, the data (if any) is read. I do nothing else at this point except read the data to keep it fast and tidy. I assumed that the data to be retrieved is strings, hence the GetStrings. You should adjust that if required, and also the types of the Lists to match.
Now that the data has been read, I act on it. If there was no data, show an appropriate message, and if there was data then I put it into multiline textboxes to show it. Note that I wrote multiline: if it was a single line textbox then only the last line would be visible. Other ways of displaying it could be more useful, for example a DataGridView - in which case I might have read the data into a DataTable or a list of some class.
What could go wrong.
In your query, you have AND DOR = #01/01/1900# - is this correct?
In your query, you have AND PAID = '0' - is PAID actually a string? If it is a number then it should be AND PAID = 0. (The DB should convert the string "0" to the number zero, but why make it do extra work?)
Now that you have multiline textboxes for the results, you can see if it just happens that the last records found happened to be blank, and are simply not visible in a single-line textbox.
Finally, are you sure it is using the correct database file?
This is my first attempt at writing a program that accesses a database from scratch, rather than simply modifying my company's existing programs. It's also my first time using VB.Net 2010, as our other programs are written in VB6 and VB.NET 2003. We're using SQL Server 2000 but should be upgrading to 2008 soon, if that's relevant.
I can successfully connect to the database and pull data via query and assign, for instance, the results to a combobox, such as here:
Private Sub PopulateCustomers()
Dim conn As New SqlConnection()
Dim SQLQuery As New SqlCommand
Dim daCustomers As New SqlDataAdapter
Dim dsCustomers As New DataSet
conn = GetConnect()
Try
SQLQuery = conn.CreateCommand
SQLQuery.CommandText = "SELECT Customer_Name, Customer_ID FROM Customer_Information ORDER BY Customer_Name"
daCustomers.SelectCommand = SQLQuery
daCustomers.Fill(dsCustomers, "Customer_Information")
With cboCustomer
.DataSource = dsCustomers.Tables("Customer_Information")
.DisplayMember = "Customer_Name"
.ValueMember = "Customer_ID"
.SelectedIndex = -1
End With
Catch ex As Exception
MsgBox("Error: " & ex.Source & ": " & ex.Message, MsgBoxStyle.OkOnly, "Connection Error !!")
End Try
conn.Close()
End Sub
I also have no problem executing a query that pulls a single field and assigns it to a variable using ExecuteScalar. What I haven't managed to figure out how to do (and can't seem to hit upon the right combination of search terms to find it elsewhere) is how to execute a query that will return a single row and then set various fields within that row to individual variables.
In case it's relevant, here is the GetConnect function referenced in the above code:
Public Function GetConnect()
conn = New SqlConnection("Data Source=<SERVERNAME>;Initial Catalog=<DBNAME>;User Id=" & Username & ";Password=" & Password & ";")
Return conn
End Function
How do I execute a query so as to assign each field of the returned row to individual variables?
You probably want to take a look at the SqlDataReader:
Using con As SqlConnection = GetConnect()
con.Open()
Using cmd As New SqlCommand("Stored Procedure Name", con)
cmd.CommandType = CommandType.StoredProcedure
cmd.Parameters.Add("#param", SqlDbType.Int)
cmd.Parameters("#param").Value = id
' Use result to build up collection
Using dr As SqlDataReader = cmd.ExecuteReader(CommandBehavior.CloseConnection Or CommandBehavior.SingleResult Or CommandBehavior.SingleRow)
If (dr.Read()) Then
' dr then has indexed columns for each column returned for the row
End If
End Using
End Using
End Using
Like #Roland Shaw, I'd go down the datareader route but an other way.
would be to loop through
dsCustomers.Tables("Customer_Information").Rows
Don't forget to check to see if there are any rows in there.
Google VB.Net and DataRow for more info.