Reputation: 65
I'm trying to solve a problem regarding types of list. First of all I have a stored procedure in my DB which does a select of a single column and I try to proceed it in my app in VB. By making a method function I declared a DataTable that loads through the SqlCommand(with the CloseConnection behavior). After that I publicly declared a List(Of String) which needs to be populated with the rows/items from the stored procedure that is on the way. Below is my snippet of the code:
Dim dt As New DataTable()
Try
If conn.State = ConnectionState.Open Then
conn.Close()
Else
conn.Open()
Dim cmd = New SqlCommand("LoadCodes", conn)
cmd.CommandType = CommandType.StoredProcedure
dt.Load(cmd.ExecuteReader(CommandBehavior.CloseConnection))
Dim collection As New List(Of DataRow)
collection = dt.AsEnumerable.ToList
LPrefix = collection.Cast(Of String)()
End If
Catch ex As Exception
MsgBox(ex.Message + vbCritical)
End Try
It's LPrefix = collection.Cast(Of String)()
where I get an exception error telling me that I can't really convert it. The old fashion way is to iterate with for/for each loop but that's not what I want for best use of performance especially if the list will have thousands of rows from a single column. So basically I want to insert those items from that DataTable to the List(Of String) without using For/For Each loop.
Running on Visual Studio 2010 Ultimate, .NET Framework 4.0.
Upvotes: 2
Views: 5932
Reputation: 18061
Assuming your DataRow
only has one column you just need to instruct ConvertAll
to cast it:
LPrefix = collection.ConvertAll(Function(x) x[0].ToString)
Thanks to Binary Worrier for c#-2-vb translation!
Upvotes: 1
Reputation: 172270
You don't need your collection
at all. Using LINQ, you can extract the first column directly out of your data table:
dt.Load(cmd.ExecuteReader(CommandBehavior.CloseConnection))
LPrefix = (From row In dt.AsEnumerable()
Select row.Field(Of String)(0)).ToList()
Of course, this might use a loop internally, but since you want to copy each value into a list of strings, you cannot do it without looping through the data rows.
Another alternative would be to use an IEnumerable(Of String)
instead of a List(Of String)
:
dt.Load(cmd.ExecuteReader(CommandBehavior.CloseConnection))
Dim LPrefixNew As IEnumerable(Of String) = _
From row In dt.AsEnumerable()
Select row.Field(Of String)(0)
You can iterate through IEnumerable just as you would through a list, but evaluation is lazy: As long as you don't access the elements, the DataTable is not traversed. So, accessing this IEnumerable is like reading the elements directly from the DataTable, just in a more convenient way.
Another word of advice: You should not try to reason about performance until you have measured it. For example, your line collection = dt.AsEnumerable.ToList
probably already loops through your entire DataTable and copies each DataRow reference into a List of DataRows; so, with this line, you already have the performance penalty that you are trying to avoid.
So, don't automatically assume that some For
loop is always slower than some single statement. Measure it, then optimize.
Upvotes: 3