November 3rd, 2010

This is the second part in a two part post series about my search for a C# alternative for the Ruby’s acts_as_tree plugin. Part one can be found here.

My goal is to use C# extension methods to add functionality for tree traversal to existing (database entity) classes. In part 1, we saw that in Ruby, mixins (like the acts_as_treen Rails plugin) can be used to add functionality to existing classes. Although (strictly speaking), mixins don’t exists in C#, we can achieve something similar to mixins with the help of extension methods.

My starting point was the AsHierarchy extension methods by Stefan Cruysberghs (as explained in part 1). However, I decided to go for a more “Ruby on Rails like” way, which means adding functionality to individual entity classes, instead of a collection of entities. Also, I only wanted to add tree functionality to classes which are somehow marked. This can be achieved by not defining an extension method on a class, but on an interface. Every class that implements that interface, has access to its extension methods. Such an interface, that can be empty and is only used for annotation, is called a marker interface.

publicinterface IHierarchyNode<T>{}

Note that the IHierarchyNode marker interface takes a type parameter, for reasons I’ll explain further on.

Whether or not the use of marker interfaces is desirable, is subject of debate. Personally, I’m not bothered by an occasional marker interface in my code. Although I’d have preferred to use an attribute instead of an interface as a marker. For example:

[HierarchyNode]publicclass Entity {}

But to my knowledge there is no way to implement extension methods for attributes in C#.

IHierarchyNode extension methods

Now that we’ve defined the IHierarchyNode interface, we can define extension methods for this interface that implement the desired behavior. First, let’s define two methods that retrieve child entities:

Child entities are selected by looking at two properties, specified in the method’s parameters idProperty and parentIdProperty. These properties represent the database columns that contain the id and parent id of an entity.

Note that the second overload is specific for DmModel entities classes. DmModel is the class used for entities in DynamicModel ORM. But the method can be easily adopted for any ORM that supports querying via IQueryable, for example LINQ to SQL or Entity Framework. For EF there is one caveat though; the EF Model does not generate foreign key properties. Stefan Cruysberghs shows in his blog post how to work around this.

Also note the use of lambda expressions to denote properties. On the web, many examples can be found of how to get a property name from a lambda expression, but this is the one I used: How to get property name from lambda expression. This is how these lambda expressions can be used:

var children = node.Children<Entity, int>(i => i.Id, i => i.ParentId)

Because the IHierarchyNode takes a generic type parameter, the compiler can check whether the instance the extension method is called on, is compatible with the input type of id and parentId lambda expressions.

Using the IHierarchyNode extension methods

All classes that implement the IHierarchyNode interface have access to the Children method defined above. Let’s look at an example of a DynamicModel entity class, used to represent posts in a WordPress database. The class definition looks like this:

Don’t pay too much attention to the attributes (e.g. “[DbColumn]”), they used needed by DynamicModel ORM; but you can use a classes from any other ORM instead. The only requirement is the existence of properties for id and the parent id values.

Now, suppose we want to retrieve children of page with ID 2 in the WordPress page tree (pages are stored in the same table as posts in WordPress, so we can use the WpPost entity):

How about relational properties in ORMs?

You might wonder if these extension methods are actually necessary when using an ORM, since almost any ORM supports traversing parent/child relationships between entities out of the box via relational properties.

Lightspeed will automatically fill the “Orders” property with orders associated with that customer. Why not use this behavior to access parent and children via a self-association?

Well, on the background, the acts_as_tree plugin actually does this: it silently adds parent/child relations to an existing ActiveRecord (the default Ruby on Rails ORM) class. This is done automatically upon calling the acs_as_tree method.

Whether to use automatic associations via a mixin-like-approach (acts_as_tree), or manually add association backed properties to your entities (default ORM approach), is a matter of taste. Personally, in the case of tree traversal, I prefer using mixins. Mainly because they allow me to add/remove behavior to a class without actually adding/removing properties or methods in entity classes.

And secondly: entity associations are primary intended be to used for relations between different entity types (database tables), instead of self-associations. Although many ORMs may allow self-associations, for me, it does not feel semantically correct to use associations for the purpose of building a tree from rows in a single table.

Conclusion

Is my C# solution as clean and elegant as Ruby’s acts_as_tree? I’m afraid not. But I’m satisfied with the result anyway. I now have a generic solution to turn any flat IQueryable of database entities into a tree with relative ease. And in the process I learned about mixins, marker interfaces and lambda property expressions as parameters :).

There probably is a more elegant implementation thinkable for the extension methods above. And maybe it is possible to approach Ruby’s mixin behavior in C# in a better way than with extension methods. But I prefer to code in an agile/iterative way, and this is step one. So I’ll keep improving the code above, and maybe there will be a sequel to this post.