how to search DataTable for specific record? - vb.net

Hi,
I have a windows form with 10 text fields and 1 combobox.
When the user selects a record in the combo-box I want to find that record in my form datatable variable (called dtBranches) then populate my 10 textfields from the datarow.
I tried this:
Dim dr As System.Data.DataRow
If mSortCode > 0 Then
dr = dtBranches.Select("SortCode='" & mSortCode & "'")
Me.txtBranch.Text = dr("Branch").ToString()
Me.txtBankName.Text = dr("BankName").ToString()
Me.txtBranchTitle.Text = dr("BranchTitle").ToString()
Me.txtReference.Text = dr("Ref").ToString
Me.txtAddr1.Text = dr("Address1").ToString
Me.txtAddr2.Text = dr("Address2").ToString
Me.txtAddr3.Text = dr("Address3").ToString
Me.txtPostCode.Text = dr("PostCode").ToString
Me.txtTelNo.Text = dr("TelephoneNumber").ToString
Me.txtTown.Text = dr("Town").ToString
Me.txtTelNo.Text = dr("TelephoneNumber").ToString
end if
but can't get it to compile...
What's the correct and best way to do this please?
thanks
Philip

DataTable.Select returns an array of DataRows. You need to declare an array to receive the result
Dim dr() As System.Data.DataRow
Of course then you need to check if you have rows returned and address the first row in the array
dr = dtBranches.Select("SortCode='" & mSortCode & "'")
If dr.Length > 0 Then
Me.txtBranch.Text = dr(0)("Branch").ToString()
Me.txtBankName.Text = dr(0)("BankName").ToString()
...... and so on ...

I would use Linq-ToDataSet and the strongly typed Field method instead:
Dim matches = From row In dtBranches
Let SortCode = row.Field(Of String)("SortCode")
Where SortCode = mSortCode
If matches.Any() Then
Dim row = matches.First()
Me.txtBranch.Text = row.Field(Of String)("Branch")
Me.txtBankName.Text = row.Field(Of String)("BankName")
Me.txtBranchTitle.Text = row.Field(Of String)("BranchTitle")
Me.txtReference.Text = row.Field(Of String)("Ref")
Me.txtAddr1.Text = row.Field(Of String)("Address1")
Me.txtAddr2.Text = row.Field(Of String)("Address2")
Me.txtAddr3.Text = row.Field(Of String)("Address3")
Me.txtPostCode.Text = row.Field(Of String)("PostCode")
Me.txtTelNo.Text = row.Field(Of String)("TelephoneNumber")
Me.txtTown.Text = row.Field(Of String)("Town")
Else
MesageBox.Show("SortCode not found.")
End If
If you want to compare case-insensitively, replace the Where above with:
Where StringComparer.OrdinalIgnoreCase.Equals(SortCode, mSortCode)
By the way, you are assigning the telephone number twice.

Related

Join string with specific word for RowFilter

I have rowfilter which i use to filter my datasource. I have couple controls which user can pick up checking specific checkboxes either to be used for Rowilter or not. Below code.
Dim ds = CType(dgvAbmessungen.PrimaryGrid.DataSource, DataSet)
Dim dtMain As DataTable = ds.Tables(0)
Dim filterStr As String = String.Empty
Dim byNummer As String = " [Nummer] like '" & txtFilterByNummer.Text.Trim() & "%'"
Dim byUser As String = " [User] = '" + cbUser.Text
Dim byCreateDateFrom As String = " [CreateDate] >= '" + CType(Convert.ToDateTime(calFrom.Value.Date), String)
Dim byCreateDateTo As String = "' ([CreateDate] < '" + CType(Convert.ToDateTime(calTo.Value.Date), String)
'select case checboxes and construct final rowfilter's string
dtMain.DefaultView.RowFilter = filterStr
Checboxes for diffrent controls to be checked:
for Nummer there is checkboxNummer
for User there is checkboxUser
for CreateDateFrom there is checkboxCreateDateFrom
for CreateDateTo there is checkboxCreateDateTo
Target is user checks one or more checboxes and filter should be constructed (string). Problem is i have no idea how to also concat "And" keywords between strings if user check more than one diffrent checboxes.
Currently i try to do it using select case. What could be the most efficient way to do so?
I would use LINQ:
Dim data = dtMain.AsEnumerable()
If checkboxNummer.Checked Then
data = data.Where(Function(row) row.Field(Of String)("Nummer").Contains(txtFilterByNummer.Text.Trim()))
End If
If checkboxUser.Checked Then
data = data.Where(Function(row) row.Field(Of String)("User") = cbUser.Text.Trim())
End If
If CreateDateFrom.Checked Then
data = data.Where(Function(row) row.Field(Of Date)("CreateDate") >= calFrom.Value.Date)
End If
If CreateDateTo.Checked Then
data = data.Where(Function(row) row.Field(Of Date)("CreateDate") < calTo.Value.Date)
End If
If you need the result as DataRow() use data.ToArray(). If you need a DataTable use:
If data.Any() Then dtMain = data.CopyToDataTable()

How to find which time value is the oldest?

In my project, at some point I tend to load all rows in my DataSet and add them to my FlowLayoutPanel in order of their "Time" Item. This is what I'm trying to do but I need the controls to be added first if their "Time" value are the oldest :
For i=1 to DataSet.Tables("myTable").Rows.Count
Dim Row as Datarow = DataSet.Tables("myTable").Select("ID = " & i)
Dim Time as Date = Row.Item("Time")
Dim NewLabel as Label
NewLabel.text = Time.ToString()
FlowLayoutPanel.Controls.Add(newLabel)
Next
How do I do that ?
You can use Linq-To-DataSet:
Dim timeOrderedRows = From row in DataSet.Tables("myTable")
Order By row.Field(Of Date)("Time")
For Each row As DataRow In timeOrderedRows
Dim Time as Date = row.Field(Of Date)("Time")
Dim Label as New Label
Label.text = Time.ToString()
FlowLayoutPanel.Controls.Add(Label)
Next
How can I do this in reverse (from newest to the oldest)
You just have to add Descending:
....
Order By row.Field(Of Date)("Time") Descending

Storing reader item in array

Dim myReader As OleDbDataReader
Dim Index As Integer
Dim status As Array
Index = 0
cmd.CommandText = "SELECT CPALLOCATIONTIME from RECORDMASTER where ID='" & TxtID.Text & "'"
cmd.CommandType = CommandType.Text
myReader = cmd.ExecuteReader()
Do While myReader.Read()
status(Index) = myReader.Item(0)
Index = Index + 1
Loop
myReader.Close()
If (Index = 2) Then
If ((status(0) = "Fp" Or status(0) = "Op") And status(1) = "OXp") Then
qText = TxtSTS.Text + "X"
Update = True
ApplicationStatus = 2
ElseIf ((status(0) = "Fp" Or status(0) = "Op") And status(1) = "FXp") Then
qText = TxtSTS.Text + "X"
Update = True
ApplicationStatus = 2
End If
Can some one please help me with status(Index) = myReader.Item(0), giving an error with conversion
You want your array to grow as elements are added. That's not what arrays are for. Use a List(Of T) instead. (See the examples on MSDN for the exact syntax.)
Make sure the data read from the reader has the correct data type. You have two ways of doing that:
Cast it (e.g. DirectCast(myReader(0), String)) or
(better) use the reader method that already returns the correct data type, e.g. myReader.GetString(0).
Redim status(0) ' < -- declare like this
Then in Loop
Redim preserve status(index)
status(Index) = myReader("Column_name")
index = index + 1
Try
status(Index) = myReader.Item(0).ToString

convert a datatable

I have a datatable like this
X,Y,Z
0,0,A
0,2,B
0,0,C
1,0,A
1,0,C
2,2,A
2,2,B
2,0,C
3,2,B
3,1,C
4,3,A
4,0,B
4,1,C
5,3,A
5,2,B
5,0,C
and I want to convert it to something like this:
X,A,B,C
0,0,2,0
1,0, ,0
2,2,2,0
3, ,2,1
4,3,0,1
5,3,2,0
I tried with dataset and linq but not I wasn't lucky.
My code for linq:
Dim q = (From c In dt _
Select c("Z") Distinct) 'I found out which categories I have in Z column (my example :A,B,C)
Dim ldt(q.Count) As DataTable
For i = 0 To q.Count - 1
Dim sfil As String = q(i).ToString
Dim r = (From c In dt _
Select c Where c("Z") = sfil)
ldt(i) = r.CopyToDataTable
Next
So now I have 3 tables (ldt(0) with values for A, ldt(1) with values for B, ldt(2) with values for C)
and I was thinking to do something like leftJoin but anything that I tried is fail.
Any solution or even a better idea?
Thanks
So a new example it would be:
I have this table:
id,Price,Item
0,0,Laptop
0,2,Tablet
0,0,Cellphone
1,0,Laptop
1,0,Tablet
2,2,Laptop
2,2,Cellphone
2,0,Tablet
3,2,Cellphone
3,1,Tablet
4,3,Laptop
4,0,Cellphone
4,1,Tablet
5,3,Laptop
5,2,Cellphone
5,0,Tablet
and I would like to convert it to this:
X,Laptop,Tablet,Cellphone
0,0,2,0
1,0, ,0
2,2,2,0
3, ,2,1
4,3,0,1
5,3,2,0
The values for each of the columns Laptop, Tablet, Cellphone are the Y values from the first table.
I hope it make more sense now.
I believe you can create a DataTable with column names corresponding to the item names. Then you group the previous DataTable by id and use each grouping to populate a row. Forgive me if I get anything wrong. I don't work with VB or DataTables that much.
Dim itemNames = (From c In dt _
Select c("Item") Distinct)
Dim newDt as DataTable = new DataTable()
Dim idColumn As DataColumn = new DataColumn()
idColumn.DataType = System.Type.GetType("System.Int32")
idColumn.ColumnName = "id"
idColumn.ReadOnly = True
idColumn.Unique = True
newDt.Columns.Add(idColumn)
For Each itemName As String In itemNames
Dim column As DataColumn = new DataColumn()
column.DataType = GetType(Nullable(Of Integer))
column.ColumnName = itemName
column.ReadOnly = True
column.Unique = False
newDt.Columns.Add(column)
Next
Dim groupingById = From row in dt
Group By Id = row("id")
Into RowsForId = Group
For Each grouping In groupingById
Dim row as DataRow = newDt.NewRow()
row("id") = grouping.Id
For Each rowForId in grouping.RowsForId
row(rowForId("Item")) = rowForId("Price")
Next
newDt.Rows.Add(row)
Next

For Each Next loop getting first row data only

I am trying to populate a dataset with data from a dynamic SQL dataset created by a code generator (PDSA). If I want the first row of data, or I use a specific "Where" clause to retrieve 1 row, I have no problem. But, when I loop through the dataset that has four entries, instead of getting the four entries, I get the first row 4 times. Any idea why?
Code Example:
Dim DS_C as New DS
Dim dr_A As DS_C.Tbl_ARow
Me.DS_C.Tbl_A.Clear()
Dim bo As PDSA.DataLayer.tbl_BDC = New PDSA.BusinessLayer.tbl_B
With bo
.ConnectionString = AppConfig.SQLConnectString
.SelectFilter = PDSA.DataLayer.tbl_BDC.SelectFilters.All
.WhereFilter = tbl_BDC.WhereFilters.None
.Load()
End With
For Each dr As DataRow In bo.DataSet.Tables(0).Rows
dr_A = DS_C.Tbl_A.NewRow
With dr_A
.CustomerID = bo.CustomerID
.FirstName = bo.FirstName
.LastName = bo.LastName
.Street = bo.Street
.City = bo.City
.State = bo.State
.ZipCode = bo.ZipCode
End With
DS_C.Tbl_A.AddTbl_ARow(dr_A)
Next
If I try to change it to use dr instead of bo , it wont accept it.
I get:
.CustomerID = dr.CustomerID(CustomerID is not a member of System.Data.DataRow)
If I try using DS_C.Tbl_ARow
For Each dr As DS_C.Tbl_ARow In bo.DataSet.Tables(0).Rows
I get type 'DS_C.Tbl_ARow' is not defined
If I try :
For Each dr As DS.Tbl_ARow In bo.DataSet.Tables(0).Rows
I get:
System.InvalidCastException = {"Unable to cast object of type 'System.Data.DataRow' to type 'TblXLMajorPerilsRow'."}
You need to access it like this:
.CustomerID = dr("CustomerID");