Filter and sort datagridview - vb.net

I have created an item list in which all items are loaded, and I need to filter the data according to the text entered in the textbox.
Please guide me how to filter and sort data, I have created the fallowing code
Private Sub loadsearchitems(item As String)
dgvsearchitem.ScrollBars = ScrollBars.Vertical
On Error Resume Next
con = New System.Data.OleDb.OleDbConnection(connectionString)
con.Open()
Dim ds As DataSet = New DataSet
Dim adapter As New OleDb.OleDbDataAdapter
sqlstr = "SELECT Imaster.icode, Imaster.iname & ' ' & MfgComTab.comname as[Iname], Imaster.unitcode, Imaster.tax,Unit.unitname FROM ((Imaster INNER JOIN MfgComTab ON Imaster.mccode = MfgComTab.mccode) INNER JOIN Unit ON Imaster.unitcode = Unit.unitcode) WHERE (Imaster.isdeleted = 'N') AND Imaster.comcode=#comcode AND Imaster.iname like '%' & #item & '%' order by iname asc "
adapter.SelectCommand = New OleDb.OleDbCommand(sqlstr, con)
adapter.SelectCommand.Parameters.AddWithValue("#comcode", compcode)
adapter.SelectCommand.Parameters.AddWithValue("#iname", item)
adapter.Fill(ds)
If ds.Tables(0).Rows.Count > 0 Then
dgvsearchitem.DataSource = ds.Tables(0)
dgvsearchitem.Columns("unitname").Visible = False
dgvsearchitem.Columns("unitcode").Visible = False
dgvsearchitem.Columns("icode").Visible = False
dgvsearchitem.Columns("tax").Visible = False
dgvsearchitem.Columns("Iname").Width = 371
Else
ds.Dispose()
End If
con.Close()
End Sub
But in the above code the application is slow because every time any text is entered a query is executed. Please tell me any solution where query is executed only once and when we enter the text it only search the items by wild card and filter it.

If you initially set the DataGridView with all the records, then you could avoid to go again to the database to extract your data in a filtered way. You have already extracted everything, so you could simply set the DataSource with a DataView filtered locally
' Code that loads initially the grid
sqlstr = "SELECT Imaster.icode, Imaster.iname .....FROM ...." ' NO WHERE HERE
....
dgvsearchitem.DataSource = ds.Tables(0).DefaultView
Now in your loadsearchitems instead of executing again a query against the database you could take the datasource and set the RowFilter property
Dim v as DataView = CType(dgvsearchitem.DataSource, DataView)
v.RowFilter = "Imaster.comcode='" & compcode & "' AND Imaster.iname like '%" & item & "'%'"
Note how the RowFilter property doesn't understand the use of parameters, so if it is possible for your comcode field to contain single quotes you need to add a some form of doubling the quotes (a String.Replace will do) to avoid a syntax error. And yes, there is no worry for Sql Injection on a DataView (it is a disconnected object and whatever your user types in the compcode field it cannot reach the database)

Related

VB.net Forecolor in every listview item

guys can you help me figure out how to put some forecolor in every listview item?
what I am trying to do is: I want to populate the listview with some forecolors in the items just like this
Example:
> ColumnHeader1 ColumnHeader2 ColumnHeader3
> Executive(W/Forecolor) texttexttext texttexttexttext
> Employee(Plain w/out FC) texttexttext texttexttexttext
here is my code:
Private Sub loadRemarks()
Try
jonsqlcon.Close()
jonsqlcon.ConnectionString = dllConstring
jonsqlcon.Open()
Dim selStaff As New SqlDataAdapter("SELECT * FROM StaffMember WHERE Staff_IDNo ='" & Notification.lblStaffID.Text & "'", jonsqlcon)
Dim setStaff As New DataSet
Dim accLvl As String
selStaff.Fill(setStaff)
accLvl = setStaff.Tables(0).DefaultView.Item(0).Item("AccessLVL").ToString
If accLvl = "2" Then
ListView1.ForeColor = Color.Aqua
End If
Dim loadChat As New SqlCommand("SELECT * FROM RemarksConvo WHERE Application_ID = '" & ClientAccountStatusViewer.txtClientID.Text & "' AND Room ='" & lvlStorage.Text & "'", jonsqlcon)
reader = loadChat.ExecuteReader
ListView1.Items.Clear()
Do While reader.Read = True
list = ListView1.Items.Add(reader(3).ToString)
list.SubItems.Add(reader(4).ToString)
list.SubItems.Add(reader(5).ToString)
list.SubItems.Add(reader(6).ToString)
Loop
Catch ex As Exception
MessageBox.Show(ex.Message, "Message", MessageBoxButtons.OK, MessageBoxIcon.Information)
End Try
End Sub
First thing you should worry is about the Sql Injection problem of your code. Do not use string concatenation to build a query text but always a parameterized text. Not only your command is more clear but there is no way that an hacker could tamper your text to wreak havoc with your database.
Second. You can bring the information about the level of your remark's author by executing a join between the two tables. The field Staff_IDNo in both tables links the records from the remarks to the table with the info about the level of the remark's author
Finally, a ListViewItem (the object returned by ListView.Items.Add) supports the ForeColor property and you can simply set the color row by row while you add items to your listview
Dim loadChat As New SqlCommand("SELECT r.*, s.AccessLVL FROM RemarksConvo r
JOIN StaffMember s ON s.Staff_IDNo = r.Staff_IDNo
WHERE r.Application_ID = #appId
AND r.Room = #room", jonsqlcon)
loadChat.Parameters.Add("#appId", SqlDbType.NVarChar).Value = ClientAccountStatusViewer.txtClientID.Text
loadChat.Parameters.Add("#room", SqlDbType.NVarChar).Value = lvlStorage.Text)
reader = loadChat.ExecuteReader
ListView1.Items.Clear()
Do While reader.Read
list = ListView1.Items.Add(reader(3).ToString)
list.ForeColor = If(reader("AccessLvl").ToString = "2", Color.Acqua, SystemColors.WindowText)
list.SubItems.Add(reader(4).ToString)
list.SubItems.Add(reader(5).ToString)
list.SubItems.Add(reader(6).ToString)
Loop

Looping through SqlDataReader returns same row twice

I'm making a VB.NET (4.6) Windows form application that collects info on our servers and allows us to do reports on it. It's coming together nicely but I've run into an issue I can't figure out. One part of the project is a service that queries the info on available Windows updates from WSUS and then stores them in an SQL database - that part works fine. I'm now trying to present this data in a DataGridView using an SqlDataReader to query the info from the database and fill up a DataTable with the response. The problem is that when I use the reader, it puts the same record in the DataTable twice. I'm not sure what I'm doing wrong, and I'm sure it's something super simple. Perhaps one of you folks can spot the problem?
Note: Earlier in the application, the updateid's are stored as unique strings in a list called dbupdateidlist, the results are stored in a DataTable called dbupTable, and the datagridview I'm trying to update is called UpdateDeetsView.
Public Sub getUpdateDetails()
For Each str As String In dbupdateidlist
Dim commGetUpdateDetails As String = "select upTableId, title, classification, description, " +
"releasedate, severity, articlenumber, url from updatedetails where updateid = '" + str + "'"
Using connObj As New SqlClient.SqlConnection(connectionString)
Using cmdObj As New SqlClient.SqlCommand(commGetUpdateDetails, connObj)
connObj.Open()
Using readerObj As SqlClient.SqlDataReader = cmdObj.ExecuteReader
While readerObj.Read
dbuptabid = readerObj("uptableid")
dbuptitle = readerObj("title")
dbupclass = readerObj("classification")
dbupdesc = readerObj("description")
dbupreleasedate = readerObj("releasedate")
dbupseverity = readerObj("severity")
dbuparticlenumber = readerObj("articlenumber")
dbupurl = readerObj("url")
row = dbupTable.NewRow()
row("uptableid") = dbuptabid
row("title") = dbuptitle
row("classification") = dbupclass
row("description") = dbupdesc
row("releasedate") = dbupreleasedate
row("severity") = dbupseverity
row("articlenumber") = dbuparticlenumber
row("url") = dbupurl
dbupTable.Rows.Add(row)
End While
End Using
connObj.Close()
End Using
End Using
Next
UpdateDeetsView.DataSource = dbupTable
End Sub
Forgive the likely terrible code, I'm an SA not a dev...
Try this:
Public Sub getUpdateDetails()
Dim sql As String = _
"SELECT DISTINCT upTableId, title, classification, description, releasedate, " & _
" severity, articlenumber, url " & _
" FROM updatedetails " & _
" WHERE updateid = #updateID"
Using cn As New SqlClient.SqlConnection(connectionString), _
cmd As New SqlClient.SqlCommand(sql, cn)
cmd.Parameters.Add("#updateID", SqlDbType.Int).Value = Int32.Parse(dbupdateidlist.First())
cn.Open()
UpdateDeetsView.DataSource = cmd.ExecuteReader()
End Using
End Sub
Note the use of DISTINCT and the complete lack of any explicit loops whatsoever.
Also note that I'm only looking at one entry in dbupdateidlist. The real source of your old bug may have been to have the the ID in that list twice.
There is no way readerObj.Read is failing to move to the next record
get the output of this and run it is SSMS
"select upTableId, title, classification, description, " +
"releasedate, severity, articlenumber, url from updatedetails where updateid = '" + str + "'"

Displaying multiple rows in multiple textboxes

I have a SQL Database table with multiple rows. I want to get the data from the rows based on the ID of that row and then present it in a certain textbox. I've got it working with Access 2013, but i've recently decided to move it to SQL.
I get an error
"There is already an open Datareader associated with this command"
Before i show you the code, it's pretty simplistic. I kind of "made" it work with access 2013, but SQL doesn't like it. The way the APP works it is paramount to have the data displayed in textboxes to make it easier to amend the data whilst being able to tab to the next box efficiently. That's why i haven't used Gridview. well, i have but that is for an asset register which is fine.
The code:
Try
conn.Open()
'***************** Populate Textboxes based on ID 1 row of PrinterDetails ***************** '
Dim sql1 As String
sql1 = "select * from PrinterDetails where ID=1"
cmd = New SQLCommand(sql1, conn)
reader = cmd.ExecuteReader
While reader.Read
'' Convert to string to prevent DBNULL errors
SNAME1.Text = reader.Item("SiteName").ToString
MAKE1.Text = reader.Item("Make").ToString
MODEL1.Text = reader.Item("Model").ToString
PRINTERIP1.Text = reader.Item("PrinterIP").ToString
PSERVER1.Text = reader.Item("Server").ToString
SHARE1.Text = reader.Item("Share").ToString
LOC1.Text = reader.Item("Location").ToString
UN1.Text = reader.Item("Username").ToString
PASS1.Text = reader.Item("Password").ToString
SUPPORT1.Text = reader.Item("Support").ToString
End While
'***************** Populate Textboxes based on ID 2 row of PrinterDetails ***************** '
Dim sql2 As String
sql2 = "select * from PrinterDetails where ID=2"
cmd = New SQLCommand(sql2, conn)
reader = cmd.ExecuteReader
While reader.Read
'' Convert to string to prevent DBNULL errors
SNAME2.Text = reader.Item("SiteName").ToString
MAKE2.Text = reader.Item("Make").ToString
MODEL2.Text = reader.Item("Model").ToString
PRINTERIP2.Text = reader.Item("PrinterIP").ToString
PSERVER2.Text = reader.Item("Server").ToString
SHARE2.Text = reader.Item("Share").ToString
LOC2.Text = reader.Item("Location").ToString
UN2.Text = reader.Item("Username").ToString
PASS2.Text = reader.Item("Password").ToString
SUPPORT2.Text = reader.Item("Support").ToString
End While
I've tried closing the connection and re-opening but that doesn't work.
Why such a bizarre query and code; your SQL query can simply be like below using a IN operator
select * from PrinterDetails where ID in (1,2);
BTW, for your issue check This MSDN Link specifically the Remarks section. In essence, you will need to close the already opened reader.

Create report from Bound DataTable

I'm fairly new to programming.
I don't plan on using Crystal Reports unless it is absolutely necessary because of license fees. I have also looked into .rdlc a little bit and to be honest it confused me. I was not sure how to get the data I wanted into the Client Report Definition using the Report Wizard. As a side note, though, I am dealing with encrypted data.
I am decrypting data in my DataTable, and would like to make a report out of the DataTable that feeds a DGV and show it in a ReportViewer. If there is a better way please let me know!
I am not sure how to use the DataTable as the data source for the report. Here ismy code for both:
Dim dt As DataTable = ds.Tables(1)
ds.DataSetName = "DataSetReport"
dt.TableName = "DataTable1"
If SearchFirsttxt.Text = "" Then
SqlCommand.CommandText = "Select * FROM PARTICIPANT WHERE LAST_NM_TXT = '" & eLast & "';"
ElseIf SearchLastTxt.Text = "" Then
SqlCommand.CommandText = "Select * FROM PARTICIPANT WHERE FIRST_NM_TXT = '" & eFirst & "';"
Else
SqlCommand.CommandText = "Select * FROM PARTICIPANT WHERE FIRST_NM_TXT = '" & eFirst & "' and LAST_NM_TXT = '" & eLast & "';"
End If
'SQL Command returns rows where values in database and textboxes are equal
SearchFirsttxt.Text = ""
SearchLastTxt.Text = ""
dFirst = clsEncrypt.DecryptData(eFirst) 'Decrypts the value entered into the SearchFirsttxt
dLast = clsEncrypt.DecryptData(eLast) 'Decrypts the value entered into the SearchLasttxt
Dim myAdapter As New SqlDataAdapter(SqlCommand) 'holds the data
myAdapter.Fill(dt) 'datatable that is populated into the holder (DataAdapter)
DataGridView1.DataSource = dt 'Assigns source of information to the gridview (DataTable)
Try
For i As Integer = 0 To dt.Rows.Count - 1
dt.Rows(i)("FIRST_NM_TXT") = clsEncrypt.DecryptData(dt.Rows(i)("FIRST_NM_TXT"))
dt.Rows(i)("LAST_NM_TXT") = clsEncrypt.DecryptData(dt.Rows(i)("LAST_NM_TXT"))
Next
Catch ex As Exception
MessageBox.Show("Either the first name or last name did not match. Please check your spelling.")
End Try
I've tried:
Dim ds As DSReportTest
ds.Tables.Add(dt)
which didn't work. The reason I am trying to rely on dt is because it contains the decrypted data.
Printing DataGridView using PrintDocument could be tedious. Refer this codeproject article to get an idea.
You can also use the DataGridView clipboard content to get the formatted values into clipboard and copy into some excel file. The below MSDN link has some example for getting clipboard content from DataGridView.
http://msdn.microsoft.com/en-us/library/system.windows.forms.datagridview.getclipboardcontent%28v=vs.110%29.aspx
If you are using vs 2010, you should not have a license issue using crystal reports when deploying an application. I assume it's not server based redistribution.
http://www.sap.com/solution/sme/software/analytics/crystal-visual-studio/implement/licensing.html

Getting selected listbox items values to display in another listbox using vb 2008

I have a form with a 2 listboxes. Here, listbox1 is populated with names of actors and actresses. If a name is selected from listbox1, listbox2 should show the title(s) of movie(s) where that name is involved. If another name is selected, listbox2 will show title(s) of movie(s) that 2 name is involved.
Call Connect()
With Me
STRSQL = "select mTitle from selectmovie where cName = '" & lstNames.SelectedItem & "'"
Try
myCmd.Connection = myConn
myCmd.CommandText = STRSQL
myReader = myCmd.ExecuteReader
If (myReader.Read()) Then
myReader.Close()
myAdptr.SelectCommand = myCmd
myAdptr.Fill(myDataTable)
lstTitle.DisplayMember = "mTitle"
lstTitle.ValueMember = "mTitle"
If myDataTable.Rows.Count > 0 Then
For i As Integer = 0 To myDataTable.Rows.Count - 1
lstTitle.Items.Add(myDataTable.Rows(i)("mTitle"))
Next
End If
End If
Catch ex As Exception
MsgBox(ex.Message)
End Try
End With
There's no error. When I select 1 item the result is correct but it leaves many space..here the screen shot of my form: http://www.flickr.com/photos/92925726#N06/8445945758/in/photostream/
The output becomes worse when I selected actor3: http://www.flickr.com/photos/92925726#N06/8445945724/in/photostream/
Your main problem seems to be that you do not clear your lstTitle control before re-loading it with the new selection. Therefore, each time you select a new name, it will add all the titles for that name to the existing list of titles that are already loaded. Also, instead of using an integer to iterate all the indexes, it is easier to just use a For Each loop:
lstTitle.Items.Clear()
For Each row As DataRow In myDataTable.Rows
lstTitle.Items.Add(row("mTitle"))
Next
However, I must also mention that you really should also be using a parameter in your query rather than dynamically building the SQL statement like that, for instance:
myCmd.CommandText = "select mTitle from selectmovie where cName = #name"
myCmd.Parameters.AddWithValue("name", lstNames.SelectedItem)
To select all the movies where all of the multiple selected actors are involved, you would need to add an additional condition to your where clause for each actor, for instance:
Dim builder As New StringBuilder()
builder.Append("select distinct mTitle from selectmovie where ")
For i As Integer = 0 to lstNames.SelectedItems.Count - 1
Dim parameterName As String = "#name" & i.ToString()
If i <> 0 Then
builder.Append("and ")
End If
builder.Append(parameterName)
builder.Append(" in (select cName from selectmovie where mTitle = m.mTitle) ")
myCmd.Parameters.AddWithValue(parameterName, lstNames.SelectedItems(i))
Next
myCmd.CommandText = builder.ToString()