how to clear the previous search from the textbox? - vb.net

I am new in vb.net. i have a database and i am running a search query of employee records when search button clicked and display that information in textbox, however when a user is not in the database, the search output is displaying the information of the previous search. the information in textbox should display blank or say "No record found" if the user is not in the record. not sure what is wrong in my code.
Try
myConnection.Open()
Dim str As String
str = "SELECT * FROM tblEmp WHERE (EmpID = '" & ADS.UserEmpID & "')"
Dim cmd As OleDbCommand = New OleDbCommand(str, myConnection)
dr = cmd.ExecuteReader
While dr.Read
If dr.HasRows > 0 Then
MessageBox.Show("user already in the system", "Warning", MessageBoxButtons.OK)
ElseIf dr.HasRows = 0 Then
MessageBox.Show("Not Onboarded", "Warning", MessageBoxButtons.OK)
End If
BGC1 = dr("PreStartChecks").ToString
BGC2 = dr("EmpName").ToString
myConnection.Close()
End While
Catch ex As Exception
MsgBox("Unable to Connect to BGC DB. You may not have access or DB not available." &
ex.ToString)
End Try

Your While loop and If statement don't make sense. Firstly, HasRows is type Boolean so testing whether it is greater than zero is nonsensical. Secondly, Read returns False if there are no rows so the only way you can get to that If statement is if there is at least one row to read so testing HasRows when you already know that there are rows is also nonsensical. The proper option here is to use just an If statement and test Read only:
If dr.Read() Then
'There is a row to read and it was just read, so you can now get the data from the reader.
Else
'There is no row to read.
End If
If you want to clear a control when there's no data, you do so in the Else block.
The "rules" about when and how to use HasRows and Read are very simple and logical:
If all you care about is whether the query result set contains data or not but you don't care what that data is, just use an If statement to test HasRows. The HasRows property is type Boolean so there's no need to compare it to anything. It already is True or False.
If there can only be zero or one row in the result set, just use an If statement to call Read and test the result. Again, it's type Boolean so there's no need to compare it to anything. If it returns True then you can access the data for the row you just read.
If there can be multiple rows and you don't want to do anything special if there are no rows then just use a While or Do While loop to call Read and access the row that was just read inside the loop.
If there can be multiple rows and you do want to do something special if there are no rows, use an If statement to test HasRows and then a While or Do While loop inside the If block to call Read. You would handle the case where there are no rows in the Else block.

Assuming that txtBGC1 and txtBGC2 are TextBoxes, you could do something like this, assuming that the query can at most return one employee
...
If dr.Read Then ' There is an employee
txtBGC1.Text = dr("PreStartChecks").ToString
txtBGC2.Text = dr("EmpName").ToString
Else ' There is no employee
txtBGC1.Text = ""
txtBGC2.Text = "No record found"
End If
myConnection.Close()

Related

Clone a datarow into same table but primary key creatin error

I'd like to allow the user to clone a record. Data is from MS SQL db and is contained in a single table with a primary key (int32) autoincrementing titled "CriteriaID". I get a CriteraID can't be null error which I would expect since it's an ID column. I tried setting it to allowdbnull in on the dataset side but no luck. How do I set it to the value needed to eventually save it into DB? If I hit new record that column is -1,-2,-3, etc. but in this case I want to clone all columns EXCEPT for the CriteriaID. I also tried NOTHING, VBNULL, and a random integer not already in DB. WOuld it be easier to use a different method?
Try
If Not IsNothing(TCriteriaBindingSource.DataSource) Then
Dim sr As DataRow() = DsCriteria.Tables("tCriteria").Select("CriteriaID = " & DsCriteria.Tables("tCriteria").Rows(TCriteriaBindingNavigator.BindingSource.Position).Item("CriteriaID"))
sr(0).Item("CriteriaID") = DBNull.Value
DsCriteria.Tables("tCriteria").NewRow()
DsCriteria.Tables("tCriteria").Rows.Add(sr(0))
End If
Catch ex As Exception
MsgBox(ex.Message)
End Try

Getting "Database is Locked" when trying to move a list of records from one table to another table in SQLite

I have a Public Sub to move a collection of records from one table to another in the same SQLite database. First it reads a record from strFromTable, then writes it to strToTable, then deletes the record from strFromTable. To speed things up, I've loaded the entire collection of records into a transaction. When the list involves moving a lot of image blobs, the db gets backed up, and throws the exception "The Database is Locked". I think what is happening is that it's not finished writing one record before it starts trying to write the next record. Since SQLite only allows one write at a time, it thows the "Locked" exception.
Here is the code that triggers the error when moving a lot of image blobs:
Using SQLconnect = New SQLiteConnection(strDbConnectionString)
SQLconnect.Open()
Using tr = SQLconnect.BeginTransaction()
Using SQLcommand = SQLconnect.CreateCommand
For Each itm As ListViewItem In lvcollection
SQLcommand.CommandText = $"INSERT INTO {strToTable} SELECT * FROM {strFromTable} WHERE id = {itm.Tag}; DELETE FROM {strFromTable} WHERE ID = {itm.Tag};"
SQLcommand.ExecuteNonQuery()
Next
End Using
tr.Commit()
End Using
End Using
When I get rid of the transaction, it executes without error:
Using SQLconnect = New SQLiteConnection(strDbConnectionString)
SQLconnect.Open()
Using SQLcommand = SQLconnect.CreateCommand
For Each itm As ListViewItem In lvcollection
SQLcommand.CommandText = $"INSERT INTO {strToTable} SELECT * FROM {strFromTable} WHERE id = {itm.Tag}; DELETE FROM {strFromTable} WHERE ID = {itm.Tag};"
SQLcommand.ExecuteNonQuery()
Next
End Using
End Using
I'm not very good with DB operations, so I'm sure there is something that needs improvement. Is there a way to make SQLite completely finish the previous INSERT before executing the next INSERT? How can I change my code to allow using a transaction?
Thank you for your help.
.
Ok ... here is the solution that I decided to go with. I hope this helps someone finding this in a search:
Dim arrIds(lvcollection.Count - 1) As String
Dim i as Integer = 0
' Load the array with all the Tags in the listViewCollection
For i = 0 to lvcollection.Count - 1
arrIds(i) = lvcollection(i).Tag 'item.Tag holds the Primary Key "id" field in the DB
Next
'build a comma-space separated string of all ids from the array of ids.
Dim strIds as String = String.Join(", ", arrIds)
Using SQLconnect = New SQLiteConnection(strDbConnectionString)
SQLconnect.Open()
Using tr = SQLconnect.BeginTransaction()
Using SQLcommand = SQLconnect.CreateCommand
SQLcommand.CommandText = $"INSERT INTO {strToTable} SELECT * FROM {strFromTable} WHERE id IN ({strIds});"
SQLcommand.ExecuteNonQuery()
SQLcommand.CommandText = $"DELETE FROM {strFromTable} WHERE ID IN ({strIds});"
SQLcommand.ExecuteNonQuery()
End Using
tr.Commit()
End Using
End Using
The IN statement allows me to pass all of the "id" values to be deleted as a batch. This solution is faster and more secure than doing them one by one with no transaction.
Thanks for the comments, and best wishes to everyone in their coding.

How to keep incrementing the same value?

Try
Dim count as Int64
Using cm As New SQLiteCommand("SELECT COUNT([RollNo]) FROM [StudentTbl]", cn)
If Not cm.ExecuteScalar() Is DBNull.Value Then
count = Convert.ToInt64(cm.ExecuteScalar())
Else
count = 0
End If
End Using
Catch ex As Exception
MsgBox(ex.Message)
Return
End Try
txtRollNo.Text = count +1
Move the count declaration outside the Try block otherwise it will not be visible outside the block. You attempt to use it outside the block.
You cannot assign a number to a .Text property. It requires a String. Convert count + 1 to a String.
Keep your database objects local so you can control that they are closed and disposed. This is particulary important for connections which are precious resources.
Why are you executing your query twice?
In most SQL languages Count will not return null. It will return 0 if there are no rows the match criteria.
It pains me to think that you have a Class level variable that is an Open connection. Get rid of it if you do. In my code you must open the connection before executing the command.
Good job converting the return value of the ExecuteScalar. Also good job passing the command text and the connection to the constructor of the command.
I am a bit leery of why you want this number. If you are expecting to use count +1 for the next primary key -- DON'T. If this is a multi-user environment then it will not work. Even if it is single user, suppose you have deleted a few records. Your method will give you a duplicate Primary Key. Set your RollNo field to auto-increment/identity and the database will do it for you.
Private Sub GetCount()
Dim count As Int64
Try
Using cn As New SQLiteConnection("Your connection string")
Using cm As SQLiteCommand = New SQLiteCommand("SELECT COUNT([RollNo]) FROM [StudentTbl]", cn)
cn.Open()
count = Convert.ToInt64(cm.ExecuteScalar())
End Using
End Using
Catch ex As Exception
MsgBox(ex.Message)
Return
End Try
txtRollNo.Text = CStr(count + 1)
End Sub

List View Population Errors

I have 3 columns that need populating when a user presses 'search' however every time that I click 'search' only the Employee ID appears, neither the 'First Name' nor the 'Last Name' are present in the List View. The data does exist in my Access Database, this is proved as the program produces a blank record instead of a null value error. The code that I am using to populate the List View is:
ds.Clear()
lstClockin.Items.Clear()
con.ConnectionString = provider & datafile
con.Open() 'Open connection to the database
sqlstatement = "SELECT * FROM [EmployeeAccounts]"
da = New OleDb.OleDbDataAdapter(sqlstatement, con)
da.Fill(ds, "allmembers") 'Fill the data adapter
con.Close()
Dim recordCount, x As Short
recordCount = 0
x = 0
recordCount = ds.Tables("allmembers").Rows.Count
With ds.Tables("allmembers")
Do Until x = recordCount
lstClockin.Items.Add(.Rows(x).Item(0))
lstClockin.Items(x).SubItems.Add(.Rows(x).Item(1))
lstClockin.Items(x).SubItems.Add(.Rows(x).Item(2))
lstClockin.Items(x).SubItems.Add(.Rows(x).Item(3))
x = x + 1
Loop
End With
The first 3 columns in the Database are, [Employee ID], [First Name] & [Last Name]
Any suggestions are welcome; however I have ruled out using a DataGridView or any control. As this program needs to use a ListView. Thankyou in advance!
There are several things that can be improved in the code:
Dim SQL = "SELECT Id, Name, Fish FROM Sample"
Using dbcon As New OleDbConnection(ACEConnStr)
Using cmd As New OleDbCommand(SQL, dbcon)
dbcon.Open()
Dim lvi As ListViewItem
myLV.SuspendLayout()
Using rdr = cmd.ExecuteReader
Do While rdr.Read
lvi = New ListViewItem(rdr.GetInt32(0).ToString)
If rdr.IsDBNull(1) Then
lvi.SubItems.Add("")
Else
lvi.SubItems.Add(rdr.GetString(1))
End If
If rdr.IsDBNull(2) Then
lvi.SubItems.Add("")
Else
lvi.SubItems.Add(rdr.GetString(2))
End If
myLV.Items.Add(lvi)
Loop
End Using
myLV.ResumeLayout()
End Using
End Using
Connections and other DB Provider objects allocate resources which need to be released or your app will leak. Using blocks for things that implement Dispose will close and dispose of them for you
There is no need for an DataAdapter, DataSet and DataTable since you are copying the data to the control. This code uses a DataReader to get the data.
Rather than SELECT * the query specifies the columns/order so it can use the Getxxxxx methods to get typed data. That doesnt matter a great deal in this case because everything gets converted to string for the ListView. lvi.SubItems.Add(rdr(COLUMN_NAME).ToString()) would also work.
It seems unlikely the ID column could be null, so the code only checks the other 2 for DbNull (another thing the DGV can handle without help).
Since the ListView is suboptimal and slow in adding items, SuspendLayout and ResumeLayout are used to minimize paints while it is populated.
I am not at all sure what ...the program produces a blank record means, but in order use a ListView like it is a grid, the View property must be Details and you have to have added 3 columns in the IDE (or manually create them in code). Nothing will show without those settings.
If the DataTable is needed/used elsewhere, you can still fill one without a DataAdpater and populate the LV from it:
...
dt.Load(cmd.ExecuteReader)
For Each row As DataRow In dt.Rows
lvi = New ListViewItem(row(0).ToString())
If DBNull.Value.Equals(row(1)) Then
lvi.SubItems.Add("")
Else
lvi.SubItems.Add(row(1).ToString())
End If
If DBNull.Value.Equals(row(2)) Then
lvi.SubItems.Add("")
Else
lvi.SubItems.Add(row(2).ToString())
End If
myLV.Items.Add(lvi)
Next
This uses a different DBNull check since it is using a DataRow and not the DataReader.

how to get data to textbox from the database

I have a form with one combo box and text box, and an SQL database
named balance with two columns; one as customername and the other as obbalance.
I had bound all of the customer name to the combo box, now what I have to do is,
when a user selects a customer name from the combo box, the text box should show the obbalance of the selected customername; here, the customer name will not be repeated - only one name per customer.
What can I do? Please help me.
Dim conectionstring As String
conectionstring = "Data Source=.\SQLEXPRESS;AttachDbFilename=C:\Documents and Settings\Administrator\My Documents\Visual Studio 2005\Projects\SHOPPROJECT\SHOPPROJECT\shop.mdf;Integrated Security=True;User Instance=True"
Dim ST As String = ComboBox1.SelectedText
Dim sqlcon As New SqlConnection(conectionstring)
Dim sqlcmd As New SqlCommand("SELECT OBBALANCE FROM BALANCE WHERE CUSTOMERNAME = " & " '" & ST & "'" & "", sqlcon)
MessageBox.Show(TextBox1.Text)
Dim result As Object
Try
sqlcon.Open()
' Dim sdr As SqlDataReader = sqlcmd.ExecuteReader()
result = sqlcmd.ExecuteScalar()
If result IsNot Nothing Then
TextBox1.Text = result.ToString()
MessageBox.Show(TextBox1.Text)
End If
Catch ex As SqlException
MessageBox.Show(ex.Message)
End Try
End Sub
I've tried this, but I can't see the value in the text box, and obbalance is a floating-point value from the SQL database.
If you're updating a text box, is this a single result (scalar value)? If so, the first thing I'd do is use ExecuteScalar not ExecuteReader. Then, use debug mode with breakpoints to get a better idea of what is actually happening. It may simply be that you're not getting any results.
Note: I'm assuming the bad coding practice (in-line sql statement, hard-coded connection string, etc.) are for clarity. If they're not, fix them.
Make the follwing changes:
Dim sqlcmd As New SqlCommand("SELECT OBBALANCE FROM BALANCE WHERE CUSTOMERNAME = '" & ST & "'", sqlcon)
TextBox1.Text = sdr.GetString(yourColumnIndex)
ComboBox1.SelectedText returns the highlighted (selected) text on the ComboBoxControl. That will be empty if you haven't use your mouse to select a portion of its text or hold the shift while you are pressing the direction keys on your keyboard. And that's probably why your query returns ZERO RECORDS.
Use the following instead:
Dim ST As String = ComboBox1.SelectedItem.Text
Set a breakpoint and ensure you are getting the value for OBBALANCE (see if you are getting any rows period might be good). Also, make sure you can only get one row, as you are iterating forward, even when you only need one value.
Better yet, consider ExecuteScalar, which only returns a single value. While you are at it, parameterize the SQL query so you don't get SQL injected.
UPDATE: Just change it here:
sdr = sqlcmd.ExecuteReader()
to something like
Dim s as String = sqlcmd.ExecuteScalar()
Then use s as your textbox value. You may have to ToString() the value or otherwise cast as string, as I believe the ExecuteScalar() returns an object.