EDIT
I have created a Hash table and I want to do a lookup and extract the Name value where ID is = line.substring(4,2).
ID Name
01 John
02 Bob
03 Joe
04 Mary
I have the following code:
Sub Main()
' Create Hashtable instance.
Dim table As Hashtable = New Hashtable
table.Add("01", "John")
table.Add("02", "Bob")
table.Add("03", "Joe")
table.Add("04", "Mary")
'-lookup and extract the Name value where ID is = line.substring(4,2)
End Sub
Agreed, use a Generic Dictionary(Of String, String).
...but, here's how to do what you asked:
Dim table As Hashtable = New Hashtable
table.Add("01", "John")
table.Add("02", "Bob")
table.Add("03", "Joe")
table.Add("04", "Mary")
Dim line As String = "abcd02efg"
Dim ID As String = line.Substring(4, 2)
If table.ContainsKey(ID) Then
Dim value As String = table(ID)
MessageBox.Show(ID & " = " & value)
Else
MessageBox.Show("Key not found! ID = " & ID)
End If
Related
all. I am a new VB.NET beginner. I am facing the issue of how to pass the dynamic SQL parameter values from the dynamic textboxes to search the data. I had added control of dynamic textboxes and labels and would like to search the data on the database table based on the dynamic textboxes value inputted from the user. Currently, I can only able to search the data from 1 dynamic textbox value only.
I want all the values from the dynamic textboxes that the user had been entered can be retrieved, and search the data based on the SQL parameter variable name and value entered by the user.
Can someone give me some solutions on how to solve this problem? I had stuck on this problem for a few days. Thank you for all the help!
What I had tried:
Private Sub FilterData()
Dim count As Integer = 0
'filterdata for radiobutton
Try
For Each TextBox As TextBox In grp2.Controls.OfType(Of TextBox)()
For Each Label As Label In grp2.Controls.OfType(Of Label)()
Using connection As New SqlConnection("connectionString")
'user key in the SQL statement
sql = TextBox1.Text
Dim sql2 As String
sql2 = sql
Dim sp1 As String() = sql.Split(New String() {"where"}, StringSplitOptions.None)
sql = sp1(0) & " where " & Label.Text & " = #parameter or " & Label.Text & " =#parameter"
If (TextBox.Text <> "") Then
count += 1
For j As Integer = 0 To count - 1
Using cmd As New SqlCommand(sql, connection)
cmd.Parameters.AddWithValue("#parameter", TextBox.Text)
'cmd.Parameters.Add("#parameter", SqlDbType.NVarChar, 20).Value = TextBox.Text
connection.Open()
Dim dt As New DataTable()
Dim reader As SqlDataReader
reader = cmd.ExecuteReader()
dt.Load(reader)
DataGridView1.DataSource = dt
End Using
Next
Else
GetData()
End If
'cmd.Dispose()
connection.Close()
End Using
Next
Next
Catch ex As Exception
'MsgBox(ex.Message)
End Try
End Sub
Firstly, if you have a 1:1 correspondence between Labels and TextBoxes then you should not be using two nested For Each loops, because that is going to pair up each and every Label with each and every TextBox. What you should be doing is creating arrays and then using a single For loop to access the pairs of controls:
Dim labels = grp2.Controls.OfType(Of Label)().ToArray()
Dim textBoxes = grp2.Controls.OfType(Of TextBox)().ToArray()
For i = 0 To labels.getUpperBound(0)
Dim label = labels(i)
Dim textBox = textBoxes(i)
'...
Next
As for build the SQL and adding the parameters, I would tend to do it something like this:
Dim labels = grp2.Controls.OfType(Of Label)().ToArray()
Dim textBoxes = grp2.Controls.OfType(Of TextBox)().ToArray()
Dim criteria As New List(Of String)
Dim command As New SqlCommand
For i = 0 To labels.getUpperBound(0)
Dim label = labels(i)
Dim textBox = textBoxes(i)
Dim parameterName = "#" & label.Text.Replace(" ", "_")
criteria.Add($"[{label.Text}] = {parameterName}")
command.Parameters.AddWithValue(parameterName, textBox.Text)
Next
Dim sql = "SELECT * FROM MyTable"
If criteria.Any() Then
sql &= " WHERE " & String.Join(" OR ", criteria)
End If
command.CommandText = sql
I think that you should begin to separate UI and data logic here is an example of implementation:
First you have a table in database:
CREATE TABLE Customer (
Id INT IDENTITY (1, 1) PRIMARY KEY,
FirstName VARCHAR (255) NOT NULL,
LastName VARCHAR (255) NOT NULL,
Phone VARCHAR (25),
Email VARCHAR (255) NOT NULL,
Street VARCHAR (255),
City VARCHAR (50),
State VARCHAR (25),
ZipCode VARCHAR (5)
);
Then you create the underlying entity in VB. Net:
Public Class Customer
Public Property Id As Integer
Public Property FirstName As String
Public Property LastName As String
Public Property Phone As String
Public Property Email As String
Public Property Street As String
Public Property City As String
Public Property State As String
Public Property ZipCode As String
End Class
Data loader
Now you need a data access component that loads records to a list of this above entity here a nice implementation:
Imports System.Data.SqlClient
Public Class CustomerDataAccess
Public Property ConStr As String
Public Sub New(ByVal constr As String)
constr = constr
End Sub
Public Function GetCustomersByCriterias(constraints As Object) As List(Of Customer)
Dim query As String = "SELECT Id, FirstName, LastName, Phone, Email, Street, City, State, ZipCode
FROM [dbo].[Customer] "
Dim result = New List(Of Customer)()
Using con = New SqlConnection(ConStr)
Using cmd = con.CreateCommand()
cmd.CommandType = CommandType.Text
cmd.CommandText = query
'' here the magic to add dynamic criteria coming from constraints
cmd.ApplyConstraints(Of Customer)(constraints)
con.Open()
LoadCustomerData(cmd, result)
End Using
End Using
Return result
End Function
Private Sub LoadCustomerData(ByVal cmd As SqlCommand, ByVal result As List(Of Customer))
Using rdr = cmd.ExecuteReader()
Dim idIdx As Integer = rdr.GetOrdinal("Id")
Dim firstNameIdx As Integer = rdr.GetOrdinal("FirstName")
Dim lastNameIdx As Integer = rdr.GetOrdinal("LastName")
Dim phoneIdx As Integer = rdr.GetOrdinal("Phone")
Dim emailIdx As Integer = rdr.GetOrdinal("Email")
Dim streetIdx As Integer = rdr.GetOrdinal("Street")
Dim cityIdx As Integer = rdr.GetOrdinal("City")
Dim stateIdx As Integer = rdr.GetOrdinal("State")
Dim zipCodeIdx As Integer = rdr.GetOrdinal("ZipCode")
While rdr.Read()
Dim item = New Customer()
item.Id = rdr.GetValueOrDefault(Of Integer)(idIdx)
item.FirstName = rdr.GetValueOrDefault(Of String)(firstNameIdx)
item.LastName = rdr.GetValueOrDefault(Of String)(lastNameIdx)
item.Phone = rdr.GetValueOrDefault(Of String)(phoneIdx)
item.Email = rdr.GetValueOrDefault(Of String)(emailIdx)
item.Street = rdr.GetValueOrDefault(Of String)(streetIdx)
item.City = rdr.GetValueOrDefault(Of String)(cityIdx)
item.State = rdr.GetValueOrDefault(Of String)(stateIdx)
item.ZipCode = rdr.GetValueOrDefault(Of String)(zipCodeIdx)
result.Add(item)
End While
End Using
End Sub
End Class
Extensions methods
Below are extensions methods referenced above that do the magic you are looking for:
DataReader extensions to make it easy to read values from SalDataReader with Dbnull exfeptional case and casting
Module DataReaderExtenions
<Extension()>
Function GetValueOrDefault(Of T)(row As IDataRecord, fieldName As String) As T
Dim ordinal = row.GetOrdinal(fieldName)
Return row.GetValueOrDefault(Of T)(ordinal)
End Function
<Extension()>
Function GetValueOrDefault(Of T)(row As IDataRecord, ordinal As Integer) As T
Return (If(row.IsDBNull(ordinal), Nothing, row.GetValue(ordinal)))
End Function
<Extension()>
Function GetValueOrDefaultSqlite(Of T)(row As IDataRecord, fieldName As String) As T
Dim ordinal = row.GetOrdinal(fieldName)
Return row.GetValueOrDefault(Of T)(ordinal)
End Function
<Extension()>
Function GetValueOrDefaultSqlite(Of T)(row As IDataRecord, ordinal As Integer) As T
Return (If(row.IsDBNull(ordinal), Nothing, Convert.ChangeType(row.GetValue(ordinal), GetType(T))))
End Function
End Module
Command extensions that lets you extract criteria from an anonymous object values:
Imports System.Reflection
Imports System.Runtime.CompilerServices
Module CommandExtensions
<Extension()>
Function AddParameter(command As IDbCommand, name As String, value As Object) As IDataParameter
If command Is Nothing Then Throw New ArgumentNullException("command")
If name Is Nothing Then Throw New ArgumentNullException("name")
Dim p = command.CreateParameter()
p.ParameterName = name
p.Value = If(value, DBNull.Value)
command.Parameters.Add(p)
Return p
End Function
<Extension()>
Function ToDictionary(data As Object) As Dictionary(Of String, Object)
If TypeOf data Is String OrElse data.[GetType]().IsPrimitive Then Return New Dictionary(Of String, Object)()
Return (From [property] In data.[GetType]().GetProperties(BindingFlags.[Public] Or BindingFlags.Instance)
Where [property].CanRead
Select [property]).ToDictionary(Function([property]) [property].Name, Function([property]) [property].GetValue(data, Nothing))
End Function
<Extension()>
Sub ApplyConstraints(Of TEntity)(cmd As IDbCommand, constraints As Object)
If constraints Is Nothing Then Return
Dim dictionary = constraints.ToDictionary()
Dim whereClause = " WHERE "
For Each kvp In dictionary
Dim columnName = kvp.Key
Dim propertyName = kvp.Key
Dim prefix = "#"c
Dim value = kvp.Value
whereClause += $"{columnName} **like** {prefix}{propertyName} AND "
cmd.AddParameter(propertyName, value)
Next
If String.IsNullOrEmpty(whereClause) Then Return
cmd.CommandText += whereClause.Remove(whereClause.Length - 5, 5)
End Sub
End Module
Example:
After coded all these stuff now you can do the following:
Dim DataGridView1 As DataGridView = New DataGridView()
Dim ConStr As String = ConfigurationManager.ConnectionStrings("MyApp").ConnectionString
Dim dal As CustomerDataAccess = New CustomerDataAccess(ConStr)
Dim criterias = New With {.FirstName = "%James%", .LastName = "%Nadin%"}
DataGridView1.DataSource = dal.GetCustomersByCriterias(criterias)
Despite all this code you are still need to bind your textbox (after naming them correctly) to a SearchEntity and use this entity to provide criterias
I hope this material can help you tackle your issue and incite you to improve your architecture & dev skills
I managed to get data from entity framework by sending table name as string as below
Public Class EFORMv1(Of t As New)
Dim dx As New EF_ORMv1.MyEntity
Function SelectByKey(Table$,Field$,Value As Object) As IEnumerable(Of t)
Dim s = "SELECT * FROM " + Table + " WHERE " + Field + " = #p1"
Dim r = dx.Database.SqlQuery(Of t)(s, New SqlParameter("#p1",Value))
Return r
End Function
End Class
I am using it like this
Dim x As New EFORMv1(Of EF_ORMv1.CONTACT)
Dim y = x.SelectByKey("CONTACT","NUM",1000).ToList
Me.dataGridView1.DataSource = y
What i am searching for is not sending the table name as string as parameter, but since I send the type in [New EFORMv1(of EF_ORMv1.CONTACT)] so I would like to use it in SelectByKey() function
Is this possible?
I want to store 100 items in a list with properties PartName and PartId.
I then want to search on PartName, as an example using the word chair. From this I then want to retrieve the value of PartId.
In the end I will end up with a PartId of 125.
How can I do this?
Code:
Dim parts As New List(Of Intialization)()
' Add parts to the list.
parts.Add(New Intialization() With {.PartName = "chair",
.PartId = 125})
You could achieve this in several ways, I´ll show you some LINQ solutions:
Dim partToSearch as String = "Chair"
Dim partId as Integer = -1
Dim init = parts.Where(Function(p) p.PartName=partToSearch).FirstOrDefault()
If init IsNot Nothing Then
partId = init.PartId
End If
Or:
Dim partToSearch as String = "Chair"
Dim partId = parts.Where(Function(p) p.PartName=partToSearch).Select(Function(v) v.PartId).FirstOrDefault()
Or you create a Dictionary like #the_lotus mentioned:
Dim partIDsByName as Dictionary(Of String, Integer)
partIDsByName = parts.ToDictionary(Function(k) k.PartName, Function(v) v.PartId)
Dim partToSearch as String = "Chair"
Dim partId = partIDsByName(partToSearch)
How do I combine column values in a dataset using LINQ into a single string with comma separated values in VB.NET ?
I have one table with following structure
ID Name
728 Jim
728 Katie
728 Rich
How do I combine these into a single row like following
ID Name
728 Jim,Katie,Rich
Please note I am using a LINQ to Dataset so please respond in the applicable syntax.
Here is an example (using LINQ to objects, but should be easy to adjust for LINQ to DataSet):
Class Record
Public Property ID As Integer
Public Property Name As String
Sub New(id As Integer, name As String)
Me.ID = id
Me.Name = name
End Sub
End Class
Sub Main()
Dim recordList As New List(Of Record)
recordList.Add(New Record(728, "Jim"))
recordList.Add(New Record(728, "Katie"))
recordList.Add(New Record(728, "Rich"))
recordList.Add(New Record(729, "John"))
recordList.Add(New Record(729, "Michael"))
Dim v = From r As Record In recordList
Group By ID = r.ID Into Records = Group
Select ID, Name = String.Join(","c, Records.Select(Function(x) x.Name))
End Sub
This should do what you want:
Dim result = list.GroupBy(Function(a) a.ID) _
.Select(Function(g) New With {.ID = g.Key, .csvList = g.Select(Function(n) n.Name) _
.Aggregate(Function(accumulation, current) accumulation + "," + current)}) _
.ToList()
This is an example using LINQ to Dataset:
Dim grouped =
From row In dt.AsEnumerable()
Group row By id = row.Field(Of Integer)("ID") Into Group
Select ID, Name = String.Join(",", From i In Group Select i.Field(Of String)("Name"))
pretty late but i also ran into same problem and this is my solution. Hope this helps someone
Dim grouped =
a.AsEnumerable().
GroupBy(Function(row) row.Field(Of Integer)("ID")).
Select(Function(group, ID)
Return New With
{
.ID= ID,
.Name= String.Join(",", group.Select(Function(row) row.Field(Of String)("Name")))
}
End Function)
I am trying to create a user modifiable string that will have already set data to replace certain patches of text
example
dim name1 as string = "John"
dim state as string = "Virginia"
dim idnumb as integer = 122
dim textlist1 as string
textlist1 = "Hello {NAME}, I see you are from {STATE}, and your id number is {ID}."
Ideally I would want to replace these tags with the set strings
I am familiar with
Replace(textlist1, "{NAME}", name1)
my question is: is this the correct way to do this or is there a method more similar to the way we do parameters in MySql
Ideally you could use StringBuilder to avoid the reallocation of a new string for every replace.
dim name1 as string = "John"
dim state as string = "Virginia"
dim idnumb as integer = 122
dim textlist1 as StringBuilder = new StringBuilder _
("Hello {NAME}, I see you are from {STATE}, and your id number is {ID}.")
textlist1.Replace("{NAME}", name1)
As supposed the StringBuilder approach is not the best for performance related comparisons
This is just a little benchmark executed via LinqPad
Sub Main
dim name1 as string = "John"
dim state as string = "Virginia"
dim idnumb as integer = 122
dim textlist1 as StringBuilder
Dim sw = new Stopwatch()
sw.Start()
for i = 0 to 100000
textlist1 = new StringBuilder("Hello {NAME}, I see you are from {STATE}, and your id number is {ID}.")
textlist1.Replace("{NAME}", name1)
textlist1.Replace("{STATE}", state)
textlist1.Replace("{ID}", idnumb.ToString())
Next
sw.Stop()
sw.Elapsed.Dump("StringBuilder.Replace")
sw = new Stopwatch()
sw.Start()
for i = 0 to 100000
Dim test = "Hello {NAME}, I see you are from {STATE}, and your id number is {ID}."
Dim test2 = test.Replace("{NAME}", name1)
Dim test3 = test2.Replace("{STATE}", state)
Dim test4 = test3.Replace("{ID}", idnumb.ToString())
Next
sw.Stop()
sw.Elapsed.Dump("String.Replace")
End Sub
StringBuilder.Replace
00:00:00.2795878
String.Replace
00:00:00.1642420
So it seems that the cost to allocate a string builder outweight the cost to use a fixed interned string. Of course the memory fragmentation caused by the immutable string behavior is not easily measurable.