YOUR FEEDBACK
Craig Balding wrote: Bruce I read your comment and couldn't quite understand how it related to the p...

SYS-CON.TV
TOP MICROSOFT .NET LINKS


Indexed LINQ
Optimizing the performance of LINQ queries using in-memory indexes

Build the Index
The first thing we need is a structure to hold our indexes. An index can be defined as a sort of "dictionary of lists." The inner list holds everything that relates to a certain indexed value. The outer dictionary holds all the different indexed values and associates them with the appropriate inner list. For example, the inner list might hold everything that starts with "A." The outer list might hold 26 items, one for each letter (a list for "A," a list for "B," and so forth). When you look up an item, you would look up by its first letter, find the list to look in, and then search through the smaller list, rather than searching through everything. Our data structure for a particular index looks like this:

Dictionary<int, List<T>>

In our actual implementation, we'll look up by int rather than string for the index. We use int because int is what the GetHashCode() method returns from all objects in .NET. One of the keys to making this work is that all objects support GetHashCode() - which lets us, while not uniquely identify an object, effectively partition it into very small groups.

Of course, there may be more than one index in our collection. So in actuality, our implementation will use a Dictionary of indexes, which gives us the following structure in the end:

protected Dictionary<string, Dictionary<int, List<T>>> _indexes
= new Dictionary<string, Dictionary<int, List<T>>>();

Building the indexes on the construction of the collection is the next step. When we build a new IndexableCollection<T>, we need to reflect what we're collecting, find out which properties are going to be indexed (by looking for the presence of the IndexableAttribute), and create the index accordingly. The following routine, called from the constructor, accomplishes that goal:

   protected void BuildIndexes()
   {
     PropertyInfo[] allProps = typeof(T).GetProperties();
     foreach (PropertyInfo prop in allProps)
     {
       object[] attributes = prop.GetCustomAttributes(true);
       foreach (object attribute in attributes)
         if (attribute is IndexableAttribute)
           _indexes.Add(prop.Name, new Dictionary<int, List<T>>());
     }
   }

Intercept Collection Adds
Once indexes are built, you need a mechanism to add data to the indexes (and eventually remove it). In our implementation, we're going to redefine the Add method in our collection:

   public new void Add(T newItem)
   {
     foreach(string key in _indexes.Keys)
     {
       PropertyInfo theProp = typeof(T).GetProperty(key);
       if (theProp != null)
       {
         int hashCode = theProp.GetValue(newItem, null).GetHashCode();
         Dictionary<int, List<T>> index = _indexes[key];
         if (index.ContainsKey(hashCode))
           index[hashCode].Add(newItem);
         else
         {
           List<T> newList = new List<T>(1);
           newList.Add(newItem);
           index.Add(hashCode, newList);
         }
       }
     }
     base.Add(newItem);
   }

The mechanics of Add are to iterate through the known indexes, and using reflection, retrieve the hash code of the appropriate property value for each field on the object we're going to index. Once we have that value (hashCode above), we look in the index to see if we have an entry yet for that hash code. If we do, we simple add the item to the list of entries that have the given hash code. If not, we create a new entry in that index based on the hash code.

Once we're done, we call the Add routine in the base class so that we have the normal behavior of add implemented. We can now go ahead and add a couple of helper methods that would help anyone trying to implement an index:

    public bool PropertyHasIndex(string propName)
    {
       return _indexes.ContainsKey(propName);
    }

    public Dictionary<int, List<T>> GetIndexByProperty(string propName)
    {
       return _indexes[propName];
    }

We need to make these public since anything that might want to implement an index on this is going to need to be able to see if a property has an index and retrieve the index if a given index exists.


About Aaron Erickson
Aaron Erickson is a principal consultant for Magenic. He is a ruthless advocate for concentrating on creating the most business value in the least amount of time when his clients entrust him to deliver a technical solution. Aaron has been delivering solutions on the Microsoft platform for over 14 years, and currently leads open source development efforts related to LINQ, including Indexes of Objects (i4o) and LINQ to Expressions (MetaLinq).

MICROSOFT .NET LATEST STORIES
As a long-time PB developer, I have successfully created or maintained many PB applications for clients and for myself. Since day one, I was impressed with the ease with which applications can be created using PowerBuilder. Although I had been exposed to Visual Studio and other client/...
TeamExpand, a developer of products complimentary to Microsoft Visual Studio Team System (VSTS), announced the commercial version of its TX Chrono, a timesheet tracking application targeted at software development organizations standardizing on the Visual Studio .NET environment. Besid...
China’s new anti-monopoly law went into effect August 1 and China-based Evermore Software, an Office wannabe, would love to haul Microsoft into court. It says it’s collecting evidence and has suggested to MarketWatch that the integration between Office and Windows might be just...
Developer Express announced the immediate availability of its reporting platform for WinForms and ASP.NET – the XtraReports Suite v2008 vol 2. Built and optimized for Visual Studio, the DevExpress suite of reporting components allows software developers to deliver cutting-edge capabi...
Poland’s Office for Competition and Consumer Protection (UOKiK) has complained to the European Commission about Microsoft Windows being on laptops to the exclusion of Linux. It suspects collusion between Microsoft and the laptop makers that Microsoft allegedly greases with rebates, a...
SUBSCRIBE TO THE WORLD'S MOST POWERFUL NEWSLETTERS
SUBSCRIBE TO OUR RSS FEEDS & GET YOUR SYS-CON NEWS LIVE!
Click to Add our RSS Feeds to the Service of Your Choice:
Google Reader or Homepage Add to My Yahoo! Subscribe with Bloglines Subscribe in NewsGator Online
myFeedster Add to My AOL Subscribe in Rojo Add 'Hugg' to Newsburst from CNET News.com Kinja Digest View Additional SYS-CON Feeds
Publish Your Article! Please send it to editorial(at)sys-con.com!

Advertise on this site! Contact advertising(at)sys-con.com! 201 802-3021


SYS-CON FEATURED WHITEPAPERS

ADS BY GOOGLE
BREAKING NEWS FROM THE WIRES
Microsoft Corp. and Nikon Corp. have signed a patent cross-licensing agreement to further the develo...