Convert the following VB code to a LINQ statement? - vb.net

I only want to return a certain number of rows into the DataTable via LINQ's Take or use it on the Rows property, but I am not sure how or where to do it: Here is the current code:
Dim dt As DataTable = GetDataTable("sp", params)
For Each dr As DataRow In dt.Rows
Dim o As New OR()
o.P = p
o.Id = dr ("A")
o.R = dr ("B")
Next
Would it be something like:
Dim dt As DataTable = GetDataTable("sp", params).AsEnumerable().Take(10)
When I run the above, I get the error:
The 'TakeIterator' start tag on line 4 position 60 does not match the end tag of 'Error'. Line 4, position 137.
Unable to cast object of type '<TakeIterator>d__3a1[System.Data.DataRow]' to type 'System.Data.DataTable'.`

If you need a DataTable:
Dim dt As DataTable = (From row in GetDataTable("sp", params) Take 10).CopyToDataTable()
If you need a List(Of [Or]) (you need the brackets since Or is a keyword)
Dim list As List(Of [Or]) = (From row In GetDataTable("sp", params)
Select New [Or]() {
o.Id = row.Field(Of Int32)("Id"),
o.R = row.Field(Of String)("R")
}).Take(10).ToList()
Edit:
is there a way I can also include a Where with the Take, for example, I have 3 statuses in my table, Open, Semi-Open, Closed, I only want to Take 10 for Open, but I want to leave Semi-Open and Closed alone. As an example Semi-Open and Closed will have 5 records combined and I will take 10 from Open, so I would get a total of 15 rows
Yes, there's a way:
Dim dt = GetDataTable("sp", params)
Dim open10 = From row In dt
Where row.Field(Of String)("Status") = "Open"
Take 10
Dim rest = From row In dt
Where row.Field(Of String)("Status") <> "Open"
Dim tblResult = open10.Concat(rest).CopyToDataTable()

Related

is that possible to calculate the value between 2 or more textbox that are grouped?

I have a table that consists of 8 columns (A, B, C, etc). Column D and E are grouped by each month. Is it possible to calculate D and E value and return the value in column G?
Here is needed more information about your scenario, as yes it’s possible, even before you make this DataTable. However in an unknown scenario, you can do that even after, as code below shows.
(And if I well understand what you want to do):
Dim dataTable As New DataTable
dataTable.Columns.Add("A")
dataTable.Columns.Add("B")
dataTable.Columns.Add("C")
dataTable.Columns.Add("D")
dataTable.Columns.Add("Result_OF_B_C")
For i As Integer = 0 To 10
dataTable.Rows.Add(dataTable.NewRow)
dataTable.Rows(dataTable.Rows.Count - 1).ItemArray =
{"ColumnA" + i.ToString, i, i + i / 2, "ColumnD" + i.ToString}
Next
Dim newDataTable As DataTable = (From R In dataTable.Rows).Select(Function(R)
Dim Cr As DataRow = CType(R, DataRow)
Cr.Item("Result_OF_B_C") = CDbl(Cr.Item("B")) + CDbl(Cr.Item("C"))
Return Cr
End Function).CopyToDataTable
DataGridView1.DataSource = newDataTable

datatable.AsEnumerable doesn't work (basic example)

Dim x = From row In f_table.AsEnumerable()
Select row("Crop")
From what I understand, the "f_table.AsEnumerable" should make my search object ("row" in this case) a datarow object. This simple example runs without any exceptions but does not find any entries (This search works if I switch to an array of datarows that have been taken from f_table, in place of f_table.AsEnumerable).
Any ideas why AsEnumerable is not allowing for searching the rows of the table?
edited/added: The following is what I have, where "emptyrows" is a subset array of rows from f_table.
Dim emptyrows_grouped = From row In emptyrows
Order By row("Date"), row("Time")
Group By New With {.date = row("Date")}.date,
New With {.crop = row("Crop")}.crop
Into Group
What i want is this form:
Dim emptyrows_grouped = From row In f_table.AsEnumerable
Where row.Field(Of String)("SamplePosition") Like "Emp%"
Order By row("Date"), row("Time")
Group By New With {.date = row("Date")}.date,
New With {.crop = row("Crop")}.crop
Into Group
It works like this:
Dim query = dt.AsEnumerable
.Where(Function(dr) dr("column name").ToString = "something").ToList
This yields a List of DataRows where this column has the value of "something"
GroupBy:
Dim query = dt.AsEnumerable
.Where(Function(dr) dr("column name").ToString = "something")
.GroupBy(Function(dr) dr("column name"))
Never mind - I'm a gigantic fool today because f_table is the wrong datatable. I used the right one and it worked.
Dim emptyrows_grouped = From row In file_table.AsEnumerable
Where row.Field(Of String)("SamplePosition") ="Empty"
Order By row("Date"), row("Time")
Group By New With {.date = row("Date")}.date,
New With {.crop = row("Crop")}.crop
Into Group
Please excuse my wasting of your time!!

Editing Datable before binding to listview in vb.net

hi this is my code to get datable from query but i need to check for some values like if there is 0 in any column then replace it with N.A.
Dim op As New cad
Dim dt As DataTable = op.Fetchbooks().Tables(0)
Dim sb As New StringBuilder()
Dim rp As System.Data.DataRow
If dt.Rows.Count > 0 Then
ListView1.DataSource = dt
ListView1.DataBind()
DropDownList1.DataSource = dt
DropDownList1.DataTextField = "Description"
DropDownList1.DataValueField = "Description"
DropDownList1.DataBind()
End if
so is there any way to check some values and edit in datable before binding ???
First, if possible i would modify your sql-query in Fetchbooks instead to replace 0 with N.A.. I assume you are querying the database.
However, if you want to do it in memory:
For Each row As DataRow In dt.Rows
For Each col As DataColumn In dt.Columns
If row.IsNull(col) OrElse row(col).ToString = "0" Then
row(col) = "N.A."
End If
Next
Next
Sure: you can iterate through the table, making whatever value replacements are appropriate (assuming that your replacement values are type-compatible with what came from the query).
Something like:
For Each row as DataRow in dt.Rows
if row("columnname") = "left" then
row("columnname") = "right"
Next
Then bind it to the grid, and you should see your updated values.
Once you have the DataTable object you can manipulate it as you need:
For Each rp In dt.Select("COLUMN_A = '0'")
rp("COLUMN_A") = "N.A."
Next
Note that this assumes that COLUMN_A is defined as a string type, not a numeric.
The challenge will be if you intend on saving this data back to it's source and you don't want the original 0 value to be saved instead of N.A.. You could add dt.AcceptChanges immediately after the above loop so that it will appear as the Fetchbooks query had these values all along.

Adding two column values to listbox in vb.net

I have a table named users which has the following columns in it
User_id,user_name,user_pwd,First_Name,Middle_Name,Last_Name and user_type.
I have dataset named dst and created a table called user in the dataset. Now I want to populate listbox with user_Name, First_Name, Last_name of each and every row in the table user.
I am able to add one column value at a time but not getting how to add multiple column values of each row to listbox
Dim dt As DataTable = Dst.Tables("user")
For Each row As DataRow In dt.Rows
lstUsers.Items.Add(row("User_Name"))
Next
Above code works perfectly but I also want to add First_name as well as last_name to the list box at the same time.
Use same approach as you have, but put all values you want in one string.
Dim dt As DataTable = Dst.Tables("user")
For Each row As DataRow In dt.Rows
Dim sItemTemp as String
sItemTemp = String.Format("{0},{1},{2}", row("User_Name"), row("First_Name"), row("Last_Name"))
lstUsers.Items.Add(sItemTemp)
Next
String.Format() function will call .ToString() on all parameters.
In this case if row(ColumnName) is NULL value then .ToString() return just empty string
You have 2 choices:
Using the ListBox:
To use the ListBox, set the font to one that is fixed width like courier new (so that the columns line up), and add the items like this:
For Each row As DataRow In dt.Rows
lstUsers.Items.Add(RPAD(row("User_Name"),16) & RPAD(row("First_Name"),16) & RPAD(row("Last_Name"),16))
Next
The RPAD function is defined like this:
Function RPAD(a As Object, LENGTH As Object) As String
Dim X As Object
X = Len(a)
If (X >= LENGTH) Then
RPAD = a : Exit Function
End If
RPAD = a & Space(LENGTH - X)
End Function
Adjust the LENGTH argument as desired in your case. Add one more for at least one space. This solution is less than ideal because you have to hard-code the column widths.
Use a DataGridView control instead of a ListBox. This is really the best option, and if you need, you can even have it behave like a ListBox by setting the option to select the full row and setting CellBorderStyle to SingleHorizontal. Define the columns in the designer, but no need to set the widths - the columns can auto-size, and I set that option in the code below. if you still prefer to set the widths, comment out the AutoSizeColumnsMode line.
The code to set up the grid and add the rows goes like this:
g.Rows.Clear() ' some of the below options are also cleared, so we set them again
g.AutoSizeColumnsMode = DataGridViewAutoSizeColumnMode.AllCells
g.CellBorderStyle = DataGridViewCellBorderStyle.SingleHorizontal
g.SelectionMode = DataGridViewSelectionMode.FullRowSelect
g.AllowUserToAddRows = False
g.AllowUserToDeleteRows = False
g.AllowUserToOrderColumns = True
For Each row As DataRow In dt.Rows
g.Rows.Add(row("User_Name"), row("First_Name"), row("Last_Name"))
Next
You might solved your problem by now but other users like me might have issue with it.
Above answers given worked for me even but I found a same answer in a simple way according to what I want..
cmd = New SqlCommand("select User_Name, First_Name, Last_Name from User")
Dim dr As SqlDataReader = cmd.ExecuteReader(YourConnectionString)
If dr.HasRows Then
Do While dr.Read
lst.Items.Add(dr.Item(0).ToString & " " & dr.Item(1).ToString & " " & dr.Item(2).ToString)
Loop
End If
This worked for me, maybe wrong way but I found it simple :)
May I suggest you use a ListView control instead of Listbox?
If you make the switch, here's a sample subroutine you could use to fill it up with the data you said you want. Adapt it the way you like; there's much room for improvement but you get the general idea:
Public Sub FillUserListView(lstUsers As ListView, Dst As DataSet)
Dim columnsWanted As List(Of String) = New List(Of String)({"User_Name", "First_Name", "Last_Name"})
Dim dt As DataTable = Dst.Tables("user")
Dim columns As Integer = 0
Dim totalColumns = 0
Dim rows As Integer = dt.Rows.Count
'Set the column titles
For Each column As DataColumn In dt.Columns
If columnsWanted.Contains(column.ColumnName) Then
lstUsers.Columns.Add(column.ColumnName)
columns = columns + 1
End If
totalColumns = totalColumns + 1
Next
Dim rowObjects(columns - 1) As ListViewItem
Dim actualColumn As Integer = 0
'Load up the rows of actual data into the ListView
For row = 0 To rows - 1
For column = 0 To totalColumns - 1
If columnsWanted.Contains(dt.Columns(column).ColumnName) Then
If actualColumn = 0 Then
rowObjects(row) = New ListViewItem()
rowObjects(row).SubItems(actualColumn).Text = dt.Rows(row).Item(actualColumn)
Else
rowObjects(row).SubItems.Add(dt.Rows(row).Item(actualColumn))
End If
lstUsers.Columns.Item(actualColumn).Width = -2 'Set auto-width
actualColumn = actualColumn + 1
End If
Next
lstUsers.Items.Add(rowObjects(row))
Next
lstUsers.View = View.Details 'Causes each item to appear on a separate line arranged in columns
End Sub

Split datatable into n datatables

I need to dynamically split a datatable into multiple datatables and the number of subsequent datatables will vary. The end user will enter a value and this will determine the number of datatables that will be derived from the original. For example: the user enters 10, the original dt has 20 rows. There will be 10 dt's with 2 rows each created. However, if the original dt has 11 rows, there would be 9 dt's with 1 row and 1 dt with 2 rows created. How can I accomplish this in vb.net without hardcoding a bunch if rules? I have read through and tried the post below but it still does not get me there.
Split a collection into `n` parts with LINQ?
You can use LINQ's GroupBy:
Dim tbl1 = New DataTable
tbl1.Columns.Add("ID", GetType(Int32))
tbl1.Columns.Add("Text", GetType(String))
For rowIndex As Int32 = 1 To 11
tbl1.Rows.Add(rowIndex, "Row " & rowIndex)
Next
Dim tableCount = 10 ' what the user entered '
Dim divisor = tbl1.Rows.Count / tableCount ' needed to identify each group '
Dim tables = tbl1.AsEnumerable().
Select(Function(r, i) New With {.Row = r, .Index = i}).
GroupBy(Function(x) Math.Floor(x.Index / divisor)).
Select(Function(g) g.Select(Function(x) x.Row).CopyToDataTable())