Indexing collections on multiple keys

Indexing collections on multiple keys

Old forum URL: forums.lhotka.net/forums/t/377.aspx


SteveInCO posted on Wednesday, June 14, 2006

Hello,

I recently started a project using CSLA 2.0. So far, I like it pretty well, but there is one common situation that I have come across that I haven't figured out an easy way to accomplish yet.

I have a collection of objects which contain what basically amounts to static data. It rarely if ever changes, so I typically load it in memory and keep it cached there to avoid having to hit the DB every time I use it. No problem, I could use a ReadOnlyListBase for that.

The problem comes in that I need to be able to retrieve objects from that collection in different ways. For instance, sometimes I will want to get an object using the Name property as the key, sometimes I might want to get it using the ID of the object. The NameValueListBase comes to mind since it allows you to use the value or the key to retrieve one another.

But that still won't do the trick, because the value is really an object with several properties on it, not just a value and a key. I can retrieve them by name easy enough, but ID <> index for the collection.

For example, I would like to do this, but using ReadOnlyBase objects:
(simplified for illustrative purposes)

MyItem.Name = "This"
MyItem.ID = 7
MyItem.Description = "A description"

MyCollection.Add MyItem

AnotherItem = MyCollection.ItemByName("This") ' Gets the object with the name field = "This"
AnotherItem = MyCollection.ItemByID(7) ' Gets the object with ID field = 7
AnotherItem = MyCollection.Item(0) ' Gets the first object in the collection

The way I have accomplished this in the past (in VB6) was to create two hidden VB collections within the MyCollection class and add a reference to the MyItem object to each during the Add method, one using the Name as the key and the other using the ID. The ItemByName and ItemById methods simply used the appropriate collection.

I realize I could write the ItemByName and ItemById methods to simply roll through the collections and return the item matching the appropriate value, but that seems rather inefficient, especially if the size of the collection grew to more than just a handful of items.

Any suggestions on how to do something similar?

BTW: I am fairly new to VB.NET as well, although I've done VB since the VB4 days, so maybe there is a way to do this that has nothing to do with the framework...

Thanks.

---Steve

cmellon replied on Thursday, June 15, 2006

Hi Steve

"I realize I could write the ItemByName and ItemById methods to simply roll through the collections and return the item matching the appropriate value, but that seems rather inefficient, especially if the size of the collection grew to more than just a handful of items."

This is the method I use.  I havent; had any perfomance issues at all with looping through a collection to find an item.  Some of my collections have hundreds of items in them.

I would suggest getting your largest static data collection, and implementing the "roll through" method and see how long it takes before dismissing the idea.

Regards

Craig

DavidDilworth replied on Thursday, June 15, 2006

Steve,

An alternative answer.  Rather than transfering your data into a Read-Only List, could you hide your "list(s)" inside a Read-Only BO in a HashTable(s) instead? 

The HashTable would be private keyed on whatever "key(s)" you need.  You could have multiple hidden lists inside the same Read-Only BO.

That way you can implement whatever lookup strategy you need in the RO class by adding the appropriate methods, but using the hidden HashTable(s) as the source of the data.

Just an idea.

SteveInCO replied on Thursday, June 15, 2006

David,

That is an interesting idea. I will look in to that a bit more.

Thanks!

---Steve

JHurrell replied on Thursday, June 15, 2006

I have to second Craig and say that this is the method I use as well. In fact, if the members of my collections do not use a single int for their PK, I typically provide an indexer using the PK, be it a composite key or Guid or whatever.

I've successfully used this looping concept on collections containing 6,000+ items with no significant performance degredation.

If you had 100,000 items, this might not make sense and you should consider another method.

- John

SteveInCO replied on Thursday, June 15, 2006

John & Craig,

Thanks for the reply.

You are correct that in most cases, rolling through the list is no big deal.

The problem comes in when you have an object that needs a cached object which also references another cached object...and so on. Things start to go up exponentially and performance goes south in a big hurry. Sometimes I'm dealing over 100,000 objects.

I ran in to a situation like that in a previous project I did. There were no performance issues at all for our typical customer, but then we installed a big customer that had one of those cached tables that contained 150 items instead of the typical 10-20. To our shock, wait times for some operations went from 1-2 seconds to 5-10 minutes!

Needless to say we had to do some quick optimizations, so I'm a little nervous about introducing the same sort of situation again.

---Steve

 

Copyright (c) Marimer LLC