tags:

views:

103

answers:

4

Hello,

I have a procedure in VB.net using VS.net 2008 which will get the list of Orders and build a XML file with the list of Orders as shown in the code below:

As the number of Orders is getting huge, I want to build the XML file for every 500 Orders

Dim Orders as List(of Orders)=DAL.GetAllOrders()
Dim Order as new Orders

Public xmlstring As New StringBuilder

If Not Orders Is Nothing Then

xmlstring.Append("<?xml version=""1.0"" encoding=""Windows-1252"" standalone=""yes""?>")
                    xmlstring.Append("<Orders>")

For Each Order In Orders

    'Build the XML File

next

     'access web service and pass the XML file

end if

Instead of building XML for all the records I want to create XML for each 500 records. I tried the following code and it is throwing an error saying Expression is of type Orders which is not a collection type.

Please help

Dim start As Integer
  For i As Integer = start To Orders.Count Step 500
    xmlstring.Append("<?xml version=""1.0"" encoding=""Windows-1252"" standalone=""yes""?>")
                    xmlstring.Append("<Orders>")

    For Each Order In Orders(i)

    'Build the XML File

    next             

  next
A: 

it is throwing an error saying Expression is of type Orders which is not a collection type.

The variable "Orders" is a collection type (List(of Orders)), but Orders(i) is not, it is an "Orders" (whatever that is, you have not posted the definition) object.

So, you need to either implement IEnumerable in your Orders class or change this line:

For Each Order In Orders(i)
Ed Swangren
A: 

How about something like this:

Dim OrdersList as List(of Orders)=DAL.GetAllOrders()


For i as int32 = 0 to OrdersList.Count() - 1
  Dim o as Orders = OrdersList(i)
  'Build your xml
  If i mod 500 = 0 Then
    'write out xml & reset your string builder
  End If

Next

*Note I changed your Orders variable as the naming convention was a little confusing and might be causing name collisions.

brendan
This will error out when reaching OrdersList.Count... makes my point to Matthew above vis-a-vis using For Each rather than For...Next for readability. Also, using "i mod 500" means your first file will contain 501 orders, not 500, because of the extra "0th" number. So, if you really want to use i for indexing, it should run from 1...Count and then use o=OrdersList(i-1).
richardtallent
One more problem here I noticed... I haven't tried it in awhile (it's against my personal taste), but IIRC, when you initialize a value *inside* the Dim statement in a loop, the initializer only happens once. So, in the above code, o will only be set once and it will keep writing it out over and over.
richardtallent
Sorry, brendan, this still won't meet the spec. With this code, you'll have 500 rows the first time (0...499), and 499 for each additional file (500...998, 999...1497, etc.).
richardtallent
A: 

I would use something like this:

for i as integer = 0 to orders.count - 1
  <create xml here and put into variable (append new XML as needed)>
  if (i mod 500 = 0 andalso not i = 0) orelse i = orders.count - 1 then
    <output XML here and clear XML variable>
  end if
next i
Sonny Boy
In most cases, writing to an xml stream is going to be more efficient than building an xml file in memory and dumping it. And, like another answer, this will result in the *first* file containing 501 orders, not 500. This code is a good example of why For Each should be preferred for maintainability, and it is just as performant these days as For...Next. No need to do all this just to make i server double-duty as an indexer and as a flow-control device.
richardtallent
+1  A: 

Some issues to resolve:

  • Step 500 will SKIP 500 rows at a time. I.e., it will write Order #1, then order #501, then #1001, etc. You'll need to track your orders-per-count yourself.
  • Your use of variable names for Order/Orders vs. the class names is confusing, and is tripping you up.
  • XML should be built via the XML tools in .NET, not by string concat. You're going to build yourself into a brick wall quickly.

Loop construct:

 Dim Orders as List(of Order) = DAL.GetAllOrders()
 If Not Orders Is Nothing Then
   Dim i As Integer = 1
   For Each order As Order In Orders
     If i=500 Then
        ' write XML footers, close the current file
        ' open the next file, write XML header
        i = 1
     Else
        i += 1
     End If
     ' write XML for this order
   Next
   ' Write final XML footer and close current file
 End If
richardtallent
Only problem with this code is that resetting your i variable to 0 may cause you to start again at the beginning. Better to check that i mod 500 = 0.
Sonny Boy
Thanks Matthew, just saw it, slapped forehead, fixed. It would not send you back to the beginning, but it would result in subsequent files having 501 orders instead of 500. No need for mod, I'm using "i" only to track the file operations, not to index the list of orders.
richardtallent
One other thing to keep in mind is to try to use for/next loops instead of for/each with indexed collections. They're quite a bit faster.
Sonny Boy
Foreach/For Each is, for all intents, just as fast as For...Next in later versions of .NET, and it is more maintainable. Current best practice in most shops now is to use doreach and if there's an itsy bitsy performance difference, it's not worth squeezing out in most cases.
richardtallent