How to display multiple rows with the same ID - vb.net

Was hoping for some help on this matter. Title pretty much explains what I'm trying to do.
I'm using MySql Database to read the data off the UserID for the purchases they have made, however I've hit a wall because I'm stuck on how to read multiple rows with the same ID.
For exmaple
1, TestProduct
1, TestProduct2
^^^ As there are more rows populated with the same ID how can I read multiple rows?
This is what I'm currently doing and I'm aware this is not working as it's only taking/finding the first ID result it finds and using that one however, I haven't needed to populate multiple rows. So I'm at a loss
SearchUser_COMMAND.Parameters.Add("#userid", MySqlDbType.VarChar).Value = Lbl_UserID.Text
Dim reader2 As MySqlDataReader
reader2 = SearchUser_COMMAND.ExecuteReader()
If reader2.Read() Then
Lbl_Active.Text = reader2(3)
Lbl_ProductName.Text = reader2(2)
Lbl_ProductExpire.Text = reader2(6)
End If
Any help on this matter would be much appreciated.
Thank very much in advance

You could make a class to hold your data, populate a List of those objects, then use some LINQ to iterate over them.
Private Class Data
Public Property Active As Boolean
Public Property Name As String
Public Property Expire As DateTime
End Class
Dim items As New List(Of Data)
If reader2.HasRows Then
While reader2.Read()
items.Add(New Data() With {.Name = CStr(reader2(2)), .Active = CBool(reader2(3)), .Expire = CDate(reader2(6))})
End While
Lbl_Active.Text = String.Join(Environment.NewLine, items.Select(Function(i) i.Active))
Lbl_ProductName.Text = String.Join(Environment.NewLine, items.Select(Function(i) i.Name))
Lbl_ProductExpire.Text = String.Join(Environment.NewLine, items.Select(Function(i) i.Expire))
End If
' maybe clear labels otherwise
For a reader with three items, this should result in something like this
Lbl_Active:
True
True
True
Lbl_ProductName:
name1
name2
name3
Lbl_ProductExpire:
date1
date2
date3
I took the liberty to assume the data types based on the names. You may have all strings in the database (you shouldn't) but then you should use strings.

Related

Can you populate a Dataset with User Input?

I need to store user input (entered from the console) to a Dataset in Visual Basic. Is this possible? I can't seem to find any information online about doing so. If anyone can point me in the right direction, that would be awesome!
EDIT: The columns in my table are FirstName, LastName, State, etc. in a table named Person.
The start of the application for the console: "Enter FirstName: ", then "EnterLastName: " then etc.
The values for the user inputs are stored in there specific variables eg. firstName, lastName, so I want to know how I can put those variables in a dataset.
Thank you.
Here is a short and basic example. Most likely it will not directly work for what you need as you will probably want to use a typed dataset among other things. Since your question does not specify a question regarding the code you may have already tried, this all I am going to provide.
Option Strict On
Module Module1
Sub Main()
Dim ds As DataSet = CreateNewDataSet()
Dim entries As New List(Of String())
For i = 1 To 3
Console.WriteLine($"Enter first column value for row {i.ToString}:")
Dim input1 As String = Console.ReadLine()
Console.WriteLine($"Enter second column value for row {i.ToString}:")
Dim input2 As String = Console.ReadLine()
entries.Add({input1, input2})
Next
entries.ForEach(Sub(x) ds.Tables(0).Rows.Add(x))
End Sub
Private Function CreateNewDataSet() As DataSet
Dim ds As New DataSet()
Dim dt As New DataTable()
Dim col1 As New DataColumn("Column1")
Dim col2 As New DataColumn("Column2")
dt.Columns.AddRange({col1, col2})
ds.Tables.Add(dt)
Return ds
End Function
End Module
If you don't know column names, you can use reflection to get names of properties of input objects. You can also use attributes to filter properties. Use DataTable.LoadDataRow method to load an array as row.
here is an example to how to do it dynamically:
Dim input As New List(Of Object)
For i = 0 To 5
Console.WriteLine("enter your first name and last name:")
input.Add(New With {.First = Console.ReadLine, .Last = Console.ReadLine})
Next
Dim myData As New DataSet
Dim table = myData.Tables.Add()
table.Columns.AddRange(input.First.GetType.GetProperties.Select(Function(p) New DataColumn(p.Name)).ToArray)
input.ForEach(Function(o) table.LoadDataRow(o.GetType.GetProperties.Select(Function(p) p.GetValue(o, Nothing)).ToArray, False))
For Each row In table.Rows
Console.WriteLine("first:{0} ,Last:{1}", row(0), row(1))
Next

List (Of T) as DataGridView.DataSource makes sorting fail

I have read some threads about this "error" but I can't figure out how to solve my problem.
I have a class that looks something like this:
Public Class Person
Public Property Name As String
Public Property PhoneNumber As string
Public Property Age As Integer
Public sub New(ByVal Values As String())
Me.Name = Values(0)
Me.PhoneNumber = Values(1)
Me.Age = Convert.ToInt32(Values(2))
End Sub
End Class
I get my data from a semicolon separated file, and i create a list of Person objects by looping this file and split on semicolon. Like this
Dim PersonsList As New List(Of Person)
For Each line in textfile..........
PersonsList.Add(New Person(line.Split(";")))
Next
When the list is complete, I tell my DataGridView that DataSource is PersonsList.
This works like a charm, but I'm not able to sort the columns.
I found this post amongst many (where the class values are not properties, which mine are) and tried that converting function which did'nt really work in my case. The right amount of rows were created, but all of the columns were blank.
What am I missing?
If you use a datatable as the data source, column sorting is automatically enabled and you can sort the data by any column:
Dim dt As New DataTable
dt.Columns.AddRange(
{
New DataColumn("Name"),
New DataColumn("Phone"),
New DataColumn("Age")
})
For Each s As String In IO.File.ReadAllLines("textfile1.txt")
Dim temprow As DataRow = dt.NewRow
temprow.ItemArray = s.Split(";"c)
dt.Rows.Add(temprow)
Next
DataGridView1.DataSource = dt

Grouping by multiple columns

I am not sure if the title is misleading but I wasn't sure how to summarise this one.
I have a table in an SQL DB where a record exists as below:
I would like to display the measurement values of this item in a gridview as below:
I thought about selecting the target values to a list (and the same for the actual values) as below:
Dim cdc As New InternalCalibrationDataContext
Dim allTargetvalues = (From i In cdc.int_calibration_records
Where i.calibration_no = Request.QueryString(0) And
i.calibration_date = Request.QueryString(1)
Select i.measure1_target, i.measure2_target, i.measure3_target).ToList()
Then joining the lists together in some way although I am unsure of how I could join the lists or even if this is the correct approach to be taking?
Well, let me first say that measure1_target, measure2_target, etc. is almost always indicative of bad database design. These should probably be in another table as the "many" end of a 1-to-many relationship with the table you posted. So to answer one of your questions: No, this is not the correct approach to be taking.
With the structure of your table in its current state, your best option is probably something like this:
Dim cdc As New InternalCalibrationDataContext
Dim allTargetValues As New List(Of Whatever)
For Each targetValue In (From i In cdc.int_calibration_records
Where i.calibration_no = Request.QueryString(0) AndAlso
i.calibration_date = Request.QueryString(1)
Select i)
allTargetValues.Add(New Whatever With {.MeasureNumber = 1,
.Target = targetValue.measure1_target,
.Actual = targetValue.measure1_actual })
allTargetValues.Add(New Whatever With {.MeasureNumber = 2,
.Target = targetValue.measure2_target,
.Actual = targetValue.measure2_actual })
allTargetValues.Add(New Whatever With {.MeasureNumber = 3,
.Target = targetValue.measure3_target,
.Actual = targetValue.measure3_actual })
Next
The Whatever class would look like this:
Public Class Whatever
Public Property MeasureNumber As Integer
Public Property Target As Integer
Public Property Actual As Integer
End Class

How to bind a DataGridView to a list of custom classes

I have a list of custom classes that I am building using a TableAdapter.
I want to add these to a DataGridView binding certain columns only.
I have tried the code below to fill and bind the data:
lAllBookings = (From r As DataRow In BookingsTableAdapter1.GetDataWithItems().Rows
Select New Booking With {.bookingID = r.Item("BookingID"), _
.itemID = r.Item("ItemID"), _
.bookedOutDate = r.Field(Of DateTime?)("BookedOutDate"), _
.bookedInDate = r.Field(Of DateTime?)("BookedInDate"), _
.identType = r.Item("IdentType"), _
.identString = r.Item("IdentString"), _
.image = r.Item("Image"), _
.complete = r.Item("Complete"), _
.notes = r.Item("Notes"), _
.itemName = r.Item("ItemName"), _
.itemBC = r.Item("ItemBarcode")}).ToList
dgvBookings.Columns("BookingID").DataPropertyName = "bookingID"
dgvBookings.Columns("ItemIdent").DataPropertyName = "itemName"
dgvBookings.Columns("BookedOut").DataPropertyName = "bookedOutDate"
dgvBookings.Columns("IdentString").DataPropertyName = "identString"
dgvBookings.DataSource = lAllBookings
Now when I do this I get the correct number of rows but all fields are blank.
I've run through a few questions on SO and a few tutorials but they all seem to do things slightly different to what I need.
Is there a way I can fill the DataGridView using my list of items?
I'd rather avoid using a DataSet if I can as I've built a lot of other code on this List<Of Class> type.
Edit - Here is the Class Booking declaration:
Public Class Booking
Public bookingID As Integer
Public itemID As Integer
Public itemName As String
Public itemBC As String
Public identType As Short
Public identString As String
Public image As Byte()
Public complete As Boolean
Public notes As String
Public bookedInDate As DateTime?
Public bookedOutDate As DateTime?
End Class
I know is really late for you but maybe it can help someone.
I had the same problem that you but using vb.net.
Finally I found the solution: Your class was not exposing properties but variables. The binding system looks for properties and can't find them so you get the empty rows.
Try to complete your class adding {get; set;} (or the Property attribute if using vb.net) and everything will work.
Hope it can be helpful.
I am not sure that you are getting in IAllBookings all the information you want. In any case, you are not passing it rightly to the dgvBookings. Here you have a couple of small codes to help you to understand how this works better:
dgvBookings.Columns.Clear()
Dim newTable As New DataTable
newTable.Columns.Add("Column1")
newTable.Columns.Add("Column2")
newTable.Columns.Add("Column3")
newTable.Rows.Add("1", "2", "3")
newTable.Rows.Add("1", "2", "3")
newTable.Rows.Add("1", "2", "3")
dgvBookings.DataSource = newTable
The newTable emulates perfectly the DataGridView structure (columns & rows) and thus it can be given as a DataSource directly.
Unlikely the case of a simple List:
dgvBookings.Columns.Clear()
Dim newList = New List(Of String)
newList.Add("1")
newList.Add("2")
newList.Add("3")
dgvBookings.DataSource = newList
You are providing less information than expected (1D vs. the expected 2D) and thus the result is not the one you want. You need to provide more information; for example: instead of relying on DataSource, you might add the rows one by one:
dgvBookings.Columns.Add("Column1", "Column1")
For Each item In newList
dgvBookings.Rows.Add(item)
Next
I hope that this answer will help you to understand better how to deal with DataGridView and with the different data sources.
-- UPDATE
Row by row option applied to your specific case.
For Each item As Booking In lAllBookings
With item
dgvBookings.Rows.Add(.bookingID.ToString(), .itemID.ToString(), .bookedOutDate.ToString(), .identString.ToString())
End With
Next

LINQ GroupBy Usage

I am using this to get all my records ordered by date:
Dim myData = db.Tbl_Exercises.Where(Function(x) x.Exercise_Employee_ID).OrderBy(Function(x) x.Exercise_Create_Date)
I loop through with this:
For Each i As Tbl_Exercise In myData
data.Add(New Object() {i.Tbl_Exercise_Type.ExType_Desc, i.Exercise_Duration})
Next
How can I group by i.Tbl_Exercise_Type.ExType_Desc so I don't have duplicates?
I tried this:
Dim myData = db.Tbl_Exercises.Where(Function(x) x.Exercise_Employee_ID).GroupBy(Function(x) x.Exercise_Type_ID)
But, I don't know how to access the variables within my loop.
Thank you.
Edit:
<EmployeeAuthorize()>
Function ExercisePieChartData() As JsonResult
' get current employee's id
Dim db1 As EmployeeDbContext = New EmployeeDbContext
Dim user1 = db1.Tbl_Employees.Where(Function(e) e.Employee_EmailAddress = User.Identity.Name).Single()
Dim empId = user1.Employee_ID
Dim activityGroups = db.Tbl_Exercises.Where(Function(x) x.Exercise_Employee_ID = empId).GroupBy(Function(x) x.Exercise_Type_ID)
Dim data = New List(Of Object)
' columns (headers)
data.Add(New Object() {"Type", "Duration"})
' Iterate through each collection of activities, grouped by activity types
For Each group In activityGroups
' Iterate through each Tbl_Exercise in the group
For Each activity In group
' Do something with an individual element
data.Add(New Object() {activity.Tbl_Exercise_Type.ExType_Desc, activity.Exercise_Duration})
Next
Next
Return Json(data, JsonRequestBehavior.AllowGet)
End Function
Edit:
' Iterate through each collection of activities, grouped by activity types
For Each group In activityGroups
Dim type = ""
Dim duration = 0
' Iterate through each Tbl_Exercise in the group
For Each activity In group
' Do something with an individual element
type = activity.Tbl_Exercise_Type.ExType_Desc
duration += activity.Exercise_Duration
Next
data.Add(New Object() {type, duration})
Next
Note: Your example isn't entirely clear, so I'm going to make a few assumptions about what you are trying to do with my solution. I'll modify it as needed as more details are made available.
From what it looks like, for each employee you are trying to get a collection of types of exercise that they have performed, and with each type of exercise you would also like a collection of the lengths of time that they spent performing these activities.
I'm going to assume that a row in Tbl_Exercises looks like this:
Public Class Tbl_Exercise
Public Property Exercise_Employee_ID As Integer
Public Property Exercise_Type_ID As Integer
Public Property Exercise_Type_Desc As String
Public Property Exercise_Duration As Integer
End Class
The attempt you make at the end is pretty close, you just need to actually use the grouping once you've created it.
What the GroupBy method has returned you here is actually an IGrouping(Of Integer, Tbl_Exercise) where the key is the Exercise_Type_ID and the value is a collection of rows that are grouped by the key. To access them its pretty simple, you just have to think of the groupings as a sort of nested collection:
Dim activityGroups = db.Tbl_Exercises.Where(Function(x) x.Exercise_Employee_ID = employeeId).GroupBy(Function(x) x.Exercise_Type_ID)
' Iterate through each collection of activities, grouped by activity types
For Each group In activityGroups
' Iterate through each Tbl_Exercise in the group
For Each activity In group
' Do something with an individual element
Console.WriteLine(activity.Exercise_Duration)
Next
Next
Obviously, you may want to do something different than print out individual collections, you may want to data bind each grouping to their own DataGrid so that you can display them separately. You may want to sort each grouping by date, or you may only want the first element from each group. Once you understand how the groupings are structured, it should be pretty easy to accomplish exactly what you're looking for.
Edit:
If you're just looking to aggregate some field in the grouping, this is very simple to accomplish without needing to resort to looping over the results. Simply adding a call to Select on top of your GroupBy will let you project the results into your desired aggregate form:
Dim data = db.Tbl_Exercises _
.Where(Function(x) x.Exercise_Employee_ID = empId) _
.GroupBy(Function(x) x.Exercise_Type_Desc) _
.Select(Function(x)
Return New With {
' x.Key will give you access to the value that the grouping is grouped by
.Exercise_Type_Desc = x.Key,
.TotalDuration = x.Sum(Function(y) y.Exercise_Duration)
}
End Function)