Hashtable Code Examples
Listing 4 is some code for filling a Hashtable with one order and its order lines. In this case, the method receives a DataReader and uses that for filling the Hashtable.
Listing 4: Code for Filling a Hashtable
Dim aDataReader As SqlDataReader = _ DbHelper.FetchOrderAndLines(id) Dim anOrder As New Hashtable() aDataReader.Read() anOrder.Add(OrderColumns.Id, _ aDataReader.GetInt32(OrderColumns.Id)) anOrder.Add(OrderColumns.CustomerId, _ aDataReader.GetInt32(OrderColumns.CustomerId)) anOrder.Add(OrderColumns.OrderDate, _ aDataReader.GetDateTime(OrderColumns.OrderDate)) aDataReader.NextResult() Dim i As Integer While aDataReader.Read anOrder.Add(OrderLineColumns.ProductId * _ Hack.Factor + i, aDataReader.GetInt32 _ (OrderLineColumns.ProductId)) anOrder.Add(OrderLineColumns.PriceForEach * _ Hack.Factor + i, aDataReader.GetSqlMoney _ (OrderLineColumns.PriceForEach).ToDecimal) anOrder.Add(OrderLineColumns.NoOfItems * _ Hack.Factor + i, aDataReader.GetInt32 _ (OrderLineColumns.NoOfItems)) anOrder.Add(OrderLineColumns.Comment * _ Hack.Factor + i, aDataReader.GetString _ (OrderLineColumns.Comment)) i += 1 End While aDataReader.Close() Return anOrder
As I said earlier in this article, I need a little hack for storing both the main information about an order and the order lines in the same Hashtable. To solve that, I added a factor (Hack.Factor) to the keys for the order lines. Of course, that is a problematic choice of what that value should be. In the code in Listing 4, I chose 1, 000,000. (You can't see that in the code; that value is in a public enumeration.) If I chose to store several orders in the same Hashtable, that would mean that I couldn't have more than 1,000,000 orders. You probably don't want to have that many orders anyway in memory, but again, this is a hack.
My friend Joe Cleland asked why I didn't use a separate Hashtable for each order's details, added to the first Hashtable. That's a good question and one that made me blush. I guess I could have said that I wanted to have just one Hashtable instead of two for each order, but I can't lie to my readers, can I?
Joe's suggestion is, of course, a much better one than my fast hack. I will add it to my tests for Part 5 in this series.
Finally, Listing 5 gives the code for when the client is inspecting the order information and navigating through all the order lines.
Listing 5: Code for Browsing the Hashtable
Dim anOrder As Hashtable = _ _service.FetchOrderAndLines(_GetRandomId()) _id = DirectCast _ (anOrder.Item(OrderColumns.Id), Integer) _customerId = DirectCast _ (anOrder.Item(OrderColumns.CustomerId), Integer) _orderDate = DirectCast _ (anOrder.Item(OrderColumns.OrderDate), Date) Dim i As Integer While anOrder.ContainsKey _ (OrderLineColumns.ProductId * Hack.Factor + i) _productId = DirectCast(anOrder.Item _ (OrderLineColumns.ProductId * _ Hack.Factor + i), Integer) _priceForEach = DirectCast(anOrder.Item _ (OrderLineColumns.PriceForEach * _ Hack.Factor + i), Decimal) _noOfItems = DirectCast(anOrder.Item _ (OrderLineColumns.NoOfItems * _ Hack.Factor + i), Integer) _comment = DirectCast(anOrder.Item _ (OrderLineColumns.Comment * _ Hack.Factor + i), String) i += 1 End While
The code in Listing 5 is much messier than the "same" code for the wrapped DataSet. This is the price you pay when you choose to go with something generic instead of something specific. The way I see it, in the generic case, you pay with more client-side code (and also with quite a lot of server-side code). In my opinion, having much client-side code is a very high price to pay. On the other hand, you will soon see that the Hashtable has good performance. Trade-offs, trade-offs....