Failed to read when no data is present - vb.net

i have this code,,its work (kind of).
Dim connString As String = ConfigurationManager.ConnectionStrings("connectionstring").ConnectionString
Dim conn As New SqlConnection(connString)
conn.Open()
Dim comm As New SqlCommand("SELECT username, Password,type FROM users WHERE username='" & TextBox1.Text & "' AND Password='" & TextBox2.Text & "'", conn)
Dim reader As SqlDataReader
reader = comm.ExecuteReader
Dim count As Integer
count = 0
While reader.Read
count = count + 1
End While
If count = 1 Then
MessageBox.Show("username and password are correct")
Form2.Show()
Form2.Label1.Text = Me.TextBox1.Text
Form2.Label2.Text = reader(2).ToString
ElseIf count > 1 Then
MessageBox.Show("username and password are duplicated")
Else
MessageBox.Show("username and password are wrong")
End If
im getting error with this line:
Form2.Label2.Text = reader(2).ToString
and error is "Invalid attempt to read when no data is present"
why its says "no data"
i have all data in database?
can someone help me to correct this code?
thank you ..

You should not be using a loop at all. There should be no way that you can get more than one record so what use would a loop be? You should be using an If statement and that's all:
If reader.Read() Then
'There was a match and you can get the data from reader here.
Else
'There was no match.
End If
If it's possible to have two records with the same username then there's something wrong with your database design and your app. That column should be unique and your app should be testing for an existing record when someone tries to register.

A SqlDataReader is a forward only data read element. The error is occurring because you're calling the reader's READ function twice; once as true to increment to 1, and a second time to get a false to fall out of the while statement. Since you're no longer in the WHILE statement, the reader had to have read the end of the result set, thus there is no data for you to read.
Consider the changed code below:
Dim connString As String = ConfigurationManager.ConnectionStrings("connectionstring").ConnectionString
Dim count As Integer = 0
Dim userType as string = ""
Using conn As New SqlConnection(connString)
conn.Open()
Using Comm as SqlCommand = conn.CreateCommand
comm.commandText = "SELECT username, Password, type FROM Users WHERE username = #UserName AND Password = #Pwd; "
comm.parameters.AddWithValue("#Username", TextBox1.Text)
comm.parameters.AddWithValue("#Password", Textbox2.text)
Dim reader As SqlDataReader
reader = comm.ExecuteReader
If reader IsNot Nothing Then
If reader.HasRows() Then
While reader.read
count = count + 1
If Not reader.IsDbNull(2) Then userType = reader(2).ToString
End While
End If
If Not reader.IsClosed Then reader.close
reader = Nothing
End If
End Using
End Using
If count = 1 Then
MessageBox.Show("username and password are correct")
Form2.Show()
Form2.Label1.Text = Me.TextBox1.Text
Form2.Label2.Text = userType
ElseIf count > 1 Then
MessageBox.Show("username and password are duplicated")
Else
MessageBox.Show("username and password are wrong")
End If
First off, SQLParameters are your friend. Learn them. They are the single easiest way to fight against SQL Injection when using the SqlClient classes.
Secondly, notice that I'm doing the actual retrieval of the data from the reader inside the WHILE loop. This ensures that there's actual data for me to read.
Third, notice the USING statements on the SqlConnection and SqlCommand objects. This helps with garbage collection, and has a couple of other benefits as well.
Finally, notice the checks I'm doing on the SqlDataReader before I ever attempt to access it. Things like that would prevent from another error appearing if you did not return any results.

Related

Trying to display a warning message on a btnsubmit_click function in vb.net when the invoice is in use

The sql script is validating the use of the invoice type and invoice. I need to add the check and message in the If (Me.txtMasterId.Text <> "0") method..
Protected Sub btnsubmit_Click(sender As Object, e As EventArgs) Handles btnsubmit.Click
If (Not DataForm.ValidateForm) Then
TransRepo.ModifyStatusName(gUser.CompanyId, Me.txtMasterId.Text, Me.txtStatusName.Text, chkIsPmtPlanFee.Checked, chkIsAttorneyFee.Checked, Me.cboStatus.SelectedValue, Me.txtId.Text, ParseDec(Me.txtExpenseLimit.Text), chkUserSpecPayTo.Checked)
ShowPanel(Me.pnlItemList, Me.Form)
ListOptions(Me.txtMasterId.Text)
SetPageHeader("List Status Name")
If (Me.txtId.Text = "0") Then
ShowConfirmation(Me.lblItemFrmMsg, "New name Added")
If (Me.txtMasterId.Text <> "0") Then
ShowConfirmation(Me.lblItemFrmMsg, "Status Name Saved")
Else
DataForm.DisplayError(Me.lblFrmErr)
End If
End If
End If
End Sub
Dim cn As MySqlConnection
Dim rdr As MySqlDataReader
Try
Dim Sql = "SELECT invoice_type.id
FROM invoice_type_fee
INNER JOIN invoice_name ON invoice_type.id = invoice_type_fee.`id`
WHERE invoice_name.`is_active` = 1
AND invoice_type_fee.`is_active` = 1
AND (invoice_type_fee.`fee_invoice_id` = #invoiceTyID
OR invoice_type_fee.`fee_late_invoicetype_id` = #invoiceTypeID LIMIT 1"
rdr.Read()
If (rdr.HasRows) Then
Dim message As String = "....."
Status.Visible = False
ClientScript.RegisterStartupScript(Me.GetType(), "alert", "alert('" & message & "');", True)
'If (invoicetype = "1") Then
End If
Catch ex As Exception
Throw
End Try
End Sub
There is no reader. You never call ExecuteReader so there's no reader to read. You seem to think that it is Read that executes the SQL but it is not. ExecuteReader executes the SQL and then Read is used to get the data from the result set. I just realised that there isn't even a command in your case. You need to create a command to execute, execute it, then read the results
There's no point getting any data though, because all you care about is whether there is data, not what it is. That means that HasRows is all you need in that case, e.g.
Using connection As New MySqlConnection("connection string here"),
command As New MySqlCommand(sql, connection)
connection.Open()
Using reader = command.ExecuteReader()
If reader.HasRows Then
'The query produced a non-empty result set.
End If
End Using
End Using
A better option would be to add a COUNT to your SQL, call ExecuteScalar and then check whether the result is zero or not.
Dim Sql = "SELECT COUNT(invoice_type.id)
FROM invoice_type_fee
INNER JOIN invoice_name ON invoice_type.id = invoice_type_fee.`id`
WHERE invoice_name.`is_active` = 1
AND invoice_type_fee.`is_active` = 1
AND (invoice_type_fee.`fee_invoice_id` = #invoiceTyID
OR invoice_type_fee.`fee_late_invoicetype_id` = #invoiceTypeID LIMIT 1"
Using connection As New MySqlConnection("connection string here"),
command As New MySqlCommand(sql, connection)
connection.Open()
If CInt(command.ExecuteScalar()) > 0 Then
'There are matching records.
End If
End Using

Reading from a database and using an if statement

The program currently reads from the database, but what I am trying to do is try to get the program to read from the database and if the field is empty then output "TBC" and if not then it will show the grade. I'm unsure of how to check what dr.Read is and use an if statement with it.
Sub GradeResult()
Dim dr As OleDbDataReader
Dim cm As New OleDbCommand
Dim cn As New OleDbConnection
cn.ConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=login.accdb"
cn.Open()
cm.CommandText = "SELECT ArGrade FROM loginDetails WHERE UserName = '" & username & "'"
cm.Connection = cn
dr = cm.ExecuteReader
dr.Read()
Label6.Text = dr.Item("ArGrade")
End Sub
Instead of using an if statement, when the user registers, the program writes TBC into the field.
dr is an instance of the OleDbDataReader class, and Read is one public method of this class. You need to call it in order to start reading the results after a query is executed against the database.
From the OleDbDataReader.Read documentation page:
Advances the OleDbDataReader to the next record.
You need to call it at least once, to get some results.
Returns
Boolean
true if there are more rows; otherwise, false.
Use it to check if you have any results at all or more results as one.
The default position of the OleDbDataReader is before the first record. Therefore, you must call Read to start accessing any data.
In your case you can check if there is any result like this:
Label6.Text = "TBC" ' standard value is no value found
if dr.Read() then ' DB contains any rows
dim arGrade = dr.Item("ArGrage")
if not IsDbNull(arGrade) then ' and the ArGrade has a value
Label6.Text = arGrade
end if
end if
And don't forget to close the reader with dr.Close.

Detecting if data exists for OleDB COUNT query

I'm trying to pull data from ACCESS database.
As it is, the code works, and gives no errors...
However, I can't seem to be able to display a messagebox if the record doesn't exist. It simply returns an empty string.
Using dbCon = New OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;" & "Data Source = '" & Application.StartupPath & "\Res\T500G.accdb'")
dbCon.Open()
Dim Query1 As String = "SELECT SUM(Total) FROM [T500] WHERE Pro=#Pro"
Dim cmd1 As OleDb.OleDbCommand = New OleDbCommand(Query1, dbCon)
cmd1.Parameters.AddWithValue("#Pro", ComboBoxBP.SelectedItem.ToString)
Dim reader As OleDb.OleDbDataReader
reader = cmd1.ExecuteReader
While reader.Read()
TextBox1.Text = reader.GetValue(0).ToString
End While
reader.Close()
dbCon.Close()
End Using
I've tried using If reader.hasrows then display result in textbox, else show messagebox etc, but it doesn't work.
If reader.HasRows Then
While reader.Read()
TextBox1.Text = reader.GetValue(0).ToString
End While
Else
MessageBox.Show("asd")
End If
If I remove the .ToString from reader.GetValue(0) I get an error if the selected item from the combobox doesn't exist in the database. Cannot convert DBNull to integer or something.
So my question is, how to display a messagebox if the record "#Pro" doesn't exist?
Thanks~
Fixed(Workaround) with this
Dim ValueReturned As String
While reader.Read()
ValueReturned = reader.GetValue(0).ToString
If ValueReturned = "" Then
MessageBox.Show("Not Found", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
Else
MetroTextBox1.Text = ValueReturned
End If
End While
Using OleDbDataReader is suboptimal for your query because it is never going to return a set of records to traverse:
Dim sql = "SELECT SUM(...=#p1"
' rather than sprinkling you connection string all over
' the app, you can make a function returning one
Using conn As OleDbConnection = GetConnection(),
cmd As New OleDbCommand(sql, GetConnection())
conn.Open())
' ToDo: Check that ComboBoxBP.SelectedItems.Count >0 before this
cmd.Parameters.AddWithValue("#p1", ComboBoxBP.SelectedItem.ToString)
' execute the query, get a result
Dim total = cmd.ExecuteScalar
' if there is no matches, OleDb returns DBNull
If total Is System.DBNull.Value Then
' no matches
MessageBox.Show("No matching records!"...)
Else
MessageBox.Show("The Total is: " & total.ToString()...)
End If
End Using ' disposes of the Connection and Command objects
Alteratively, you could use If IsDBNull(total) Then.... If you want, you can also convert it:
Dim total = cmd.ExecuteScalar.ToString()
' DBNull will convert to an empty string
If String.IsNullOrEmpty(total) Then
MessageBox.Show("No Soup For You!")
Else
...
End If
You could change your query to (this is for SQL-Server):
IF EXISTS (SELECT * FROM [T500] WHERE Pro = #Pro) SELECT SUM(Total) FROM [T500] WHERE Pro = #Pro ELSE SELECT 'Not Found'
And change your code to:
Dim ValueReturned As String
While reader.Read()
ValueReturned = reader.GetValue(0).ToString
End While
If ValueReturned Is Nothing OrElse ValueReturned = "Not Found" Then
MessageBox.Show("Not Found", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
Else
TextBox1.Text = ValueReturned
End If

Retrieve data from database in asp.net using vb

Below is the code for fetching the data into textbox but its not working it shows error no data exits row/column whereas data and datafield are perfectly alright.
Please help.
Dim Connection As OleDbConnection
Connection = New OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & Server.MapPath("/db/QardanHasana.mdb"))
Connection.Open()
Dim ejamaatregcmd As OleDbCommand
Dim ejamaatregdtrdr As OleDbDataReader
ejamaatregcmd = New OleDbCommand("SELECT ITSData.[EJamaatID], ITSData.[ITSFirstName] FROM ITSData WHERE EjamaatID= #EjamaatID", Connection)
ejamaatregcmd.Parameters.Add(New OleDbParameter("#EjamaatID", txtEjamaatID.Text))
ejamaatregdtrdr = ejamaatregcmd.ExecuteReader()
If ejamaatregdtrdr.HasRows Then
txtFirstName.Text = ejamaatregdtrdr.item("ITSFirstName").ToString()
end if
A DataReader needs a call to Read to position itself on the first record retrieved
ejamaatregdtrdr = ejamaatregcmd.ExecuteReader()
If ejamaatregdtrdr.HasRows Then
ejamaatregdtrdr.Read()
txtFirstName.Text = ejamaatregdtrdr.item("ITSFirstName").ToString()
End if
By the way, Read returns false if there are no rows to read, so you could remove the test for HasRows and write simply
ejamaatregdtrdr = ejamaatregcmd.ExecuteReader()
If ejamaatregdtrdr.Read() Then
txtFirstName.Text = ejamaatregdtrdr.item("ITSFirstName").ToString()
End if
Another suggestion to improve your code is to start using the Using Statement
Using Connection = New OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;....")
Using ejamaatregcmd = new OleDbCommand("SELECT ITSData.[EJamaatID], ITSData.[ITSFirstName] FROM ITSData WHERE EjamaatID= #EjamaatID", Connection)
Connection.Open()
ejamaatregcmd.Parameters.Add(New OleDbParameter("#EjamaatID", txtEjamaatID.Text))
Using ejamaatregdtrdr = ejamaatregcmd.ExecuteReader()
If ejamaatregdtrdr.Read() Then
txtFirstName.Text = ejamaatregdtrdr.item("ITSFirstName").ToString()
End if
End Using
End Using
End Using
The using statement is invaluable to help you to close and dispose the disposable objects like the connection, the command and the reader. Lacking a proper dispose your code uses more memory and locks resources resulting in a more unstable application.
Before reading data from a DataReader, you need to move the row to the first row by calling the Read method. It returns true if data exist, so you don't need to check the HasRows property:
ejamaatregdtrdr = ejamaatregcmd.ExecuteReader()
If ejamaatregdtrdr.Read() Then
txtFirstName.Text = ejamaatregdtrdr.Item("ITSFirstName").ToString()
End if
I'll generally do something like the following
Function GetResult(ID As string) As String
GetResult = "No Data" 'Default Result
Dim conn As System.Data.OleDb.OleDbConnection = *NewConnectionObject*
Dim comm As System.Data.OleDb.OleDbCommand = *NewCommmandObject*
comm.Parameter.AddWithValue("#Parametername",ID)
Using reader As System.Data.OleDb.OleDbDataReader = comm.ExecuteReader()
If reader.HasRows Then
'Reader has data, so iterate through it
GetResult = ""
while reader.read
GetResult += reader("FirstName")
End While
Else
'Either Do Nothing - Default Result will show
'Throw New System.Exception("Empty Data") 'Try Catch Statement have overhead.. so it's not a popular methodology
'Or Log Something..
End If
End Using
If conn.state = connection.open Then
conn.close
End
End Function

Why is my ELSE statement being skipped?

I've been trying to use an IF/ELSE statement to query my MySQL database, but can't seem to figure out why the ELSE statement is being ignored by VB. Here's the code - any help would be appreciated:
dbConn = New MySqlConnection("Server=" & FormLogin.ComboBoxServerIP.SelectedItem & ";Port=3306;Uid=qwertyuiop;Password=lkjhgfdsa;Database=zxcvbnm")
Dim account As Boolean = True
If dbConn.State = ConnectionState.Open Then
dbConn.Close()
End If
dbConn.Open()
Dim dbQuery As String = "SELECT * FROM customer WHERE accountNumber = '" & TextBoxSearch.Text & "';"
Dim dbData As MySqlDataReader
Dim dbAdapter As New MySqlDataAdapter
Dim dbCmd As New MySqlCommand
dbCmd.CommandText = dbQuery
dbCmd.Connection = dbConn
dbAdapter.SelectCommand = dbCmd
dbData = dbCmd.ExecuteReader
While dbData.Read()
If dbData.HasRows() = True Then
MessageBox.Show("Customer Account Found!")
Else
MessageBox.Show("No Customer Records Found! Please try again!")
dbData.Close()
End If
End While
My intent is to replace the messagebox in the "IF" clause with the code that will populate my form with the data from the database.
That's because you are already reading it:
While dbData.Read()
If dbData.HasRows() = True Then
MessageBox.Show("Customer Account Found!")
Else
MessageBox.Show("No Customer Records Found! Please try again!")
dbData.Close()
End If
End While
If your reader has no records, the whole While loop will be skipped.
Try it the other way around:
If dbData.HasRows Then
While dbData.Read()
'looping through records here
End While
Else
MessageBox.Show("No Customer Records Found! Please try again!")
End If
And also the obligatory note: Don't keep your connections open and alive. Use the Using End Using bracket to automatically close your disposable objects.
I wouldn't say it's skipping your else clause, but it could be evaluating your if condition differently that you expect.
Personally, I don't like comparing anything to True. If you drop the = true, does it work?