views:

61

answers:

3

ok this is the thing I have right now which is working quite well except its a bit slow:

Public Function GetList() As List(Of SalesOrder)
Try
    Dim list As New List(Of SalesOrder)

    Dim ds As DataSet

    ds = cls.GetSalesOrderList 'CLS is the data access class


    For i = 0 To ds.Tables(0).Rows.Count - 1

        Dim row As DataRow = ds.Tables(0).Rows(i)
        Dim kk As SalesOrder = New SalesOrder()


        kk.ID = Val(row.Item("id") & "")
        kk.SalesOrderNo = row.Item("salesorderid") & ""
        kk.SalesOrderDate = row.Item("OrderDate") & ""
        kk.CustomerId = Val(row.Item("customerid") & "")

        list.Add(kk)

    Next
    Return list

    Catch ex As Exception
        Throw ex
    End Try

End Function

Now once I start retrieving more than 10000 records from the table, the loop takes long time to load values into generic class. Is there any way that I can get rid of loop? Can I do something like the following with the generic class?

txtSearch.AutoCompleteCustomSource.AddRange(Array. ConvertAll(Of DataRow, String)(BusinessLogic.ToDataTable.ConvertTo(WorkOr derList).Select(), Function(row As DataRow) row("TradeContactName"))) 
A: 

I would have thought the problem isn't with doing a loop but with volumes of data. Your loop method seems to process each bit of data only once so there isn't any massive efficiency crash (such as looping over the dataset once and then again for each row or that kind of thing). Any method you choose is at the end of the day going to have to loop through all your data.

Their methods might be slightly more efficient than yours but they aren't going to be that much more so I'd think. I'd look at whether you can do some refactoring to reduce your data set (eg limit it to a certain period or similar) or whether you can do whatever searching or aggregating of that list you intend in the database instead of in code. eg if you're just going to sum the values of that list then you can almost certainly do it better by having a stored procedure that will do the summing on the database rather than in the code.

I know this hasn't directly answered your question but this is mainly because I don't know of a more efficient method. I took the question as asking for optimisation in general though rather than how to do this specific one. :)

Chris
Thanks for the reply. But Im sure the answer of my question is hidden somewhere in the following code. Its just that I am not been able to convert this logic into my generic class code.The following code adds keywords into textbox for the searching without loop. The values are coming from generic class collection (List).txtSearch.AutoCompleteCustomSource.AddRange(Array. ConvertAll(Of DataRow, String)(BusinessLogic.ToDataTable.ConvertTo(WorkOr derList).Select(), Function(row As DataRow) row("TradeContactName")))
NomanEagle
A: 

Converting the loop into some kind of LINQ construct isn't necessarily going to improve performance if you're still enumerating over every row at once. You could return IEnumerable(Of SalesOrder) if you don't need to give the consumer the ability to add/remove from the list (which it looks like might be the case), and then in that case you could create an enumerator to handle this. That way, the dataset is loaded all at once, but the items are only converted into objects when they're being enumerated over, which may be part of your performance hit.

Something like this:

Return ds.Tables(0).Rows.Select(Function(dr As DataRow) Return New SalesOrder ... );

My VB with LINQ is a little rusty, but something to that effect, where the ... is the code to instantiate a new SalesOrder. That will only create a new SalesOrder object as the IEnumerable(Of SalesOrder) is being enumerated over (lazy, if you will).

Paul
oh I see. But I have never used IEnumerable. I checked the following link but its little complicated. My class is pretty straight forward without any add/remove methods. http://msdn.microsoft.com/en-zs/library/system.collections.ienumerable.aspx
NomanEagle
Btw, in C# it'd be return ds.Tables[0].Rows.Select(dr => new SalesOrder(dr)); where you have a constructor overload that populates your object from a datarow. You can do this multiple ways, depends on your style. And the Select() statement here is implicitly convertable to IEnumerable(Of T) so just set the return type of the method to IEnumerable(Of SalesOrder) if you use this method -- that's it.
Paul
How would select() recognize which property of generic class has to be filled with which field of dataset?
NomanEagle
Your idea looks great but Im struglling to implement it into my code. May be because Im very new in IEnumerable. Can you help me with that. It will be a great help if you can convert my getList() function into an IEnumerable. Im ok even with C# code. Then I will have some better idea about the implementation. any possibility?
NomanEagle
That's the "..." in the example above. Either you could do it in the lambda body (if the property count is small enough to be readable), or you could create a constructor overload on SalesOrder that takes a DataRow and does it there, or you could create a method that converts a DataRow into a SalesOrder and pass it as a delegate to Select (i.e. if your function is called DrToOrder(dr As DataRow), then call Rows.Select(DrToOrder). You may need to use AddressOf in VB.)
Paul
A: 

Hey Paul, You mean something like below code

Dim list As New List(Of SalesOrder)

Dim kk As SalesOrder = New SalesOrder()

function DrToOrder(dr as datareader)

     kk.ID = Val(dr.Item("id") & "") 
     kk.SalesOrderNo = dr.Item("salesorderid") & "" 
     list.Add(kk) 

end function

function LoadData()

datareader.Rows.Select(DrToOrder)

end function

Are you talking about something like above code?

NomanEagle
Your formatting is messed up.
Jouke van der Maas