Part of the reason I’ve been quiet on the blog lately (apart from work, travel, family life, ill dogs, and just general laziness) is that I’ve been working on a reasonably large ECO/ASP.NET application for use internally in Borland. Eventually I’d like to publish the source code (inspired as I am by Peter Morris) but trust me, you wouldn’t want to see it in its current state.
Anyway, back to the point. Being a web app, part of it follows a fairly common web standard of organising content in a hierarchy of categories that users can use to navigate down into more specific areas. Think of the directory structure at Yahoo in the screenshot below

Anyway, this was relatively easy to implement in a model: a Category class that has an auto-association (ie. an association to itself) such that a Category can have 0..* child categories, and a Category can have 0..1 parent categories. It was also relatively easy to set up in ASP.NET so I could browse my way up and down these categories.

What had me stumped for awhile were the breadcrumbs. Breadcrumbs? Look in the Yahoo screenshot above. Near the top, it has a list of all the ancestor categories as links, so you can work your way back up to where you came from. I wanted to be able to get a list of the Category objects that make up the path from a specific Category all the way to the root. In the screenshot, it’s Directory, Computers and Internet, Programming and Development, Languages, Delphi from least specific down to most specific. Once I had this in a handle, I could bind it to an ASP.NET Repeater component and Robert’s your mother’s brother. I didn’t only need to access this path for the breadcrumbs, but that’s a nice, visible example of what I needed.
I eventually came up with some fairly convoluted code that walked up the Parent association, adding each to a handle as I went (which involved some pretty funky casting along the way). That worked, but it left a fairly foul taste in my mouth. I thought ECO was supposed to stop me from having to write this sort of pointless plumbing code?
Well, obviously if there wasn’t a better way I wouldn’t be writing this article. After some help from Jesper and Jonas (thanks guys!) here’s my current solution. I’m sure there are others, but I’m kinda fond of this one at the moment.

I’ve added a Derived Association, in fact another auto-association, called Path and made it uni-directional. When you reference this association you should get back all categories from the root down to the current Category. To make this happen, the Derivation OCL for the Path association looks like this:
if self.Parent.isNull then
self->asSet
else
self.Parent.Path->including(self)
endif
If the current Category is the root, its Parent will be null, and as a result we return a collection of just the current Category. However, if we are somewhere down the tree, then we use the including operator to add the current Category to its Parent’s Path collection (ie. we’re recursively calling this derived association).
Works like a bought one, as you can see in the screenshot below. The top left grid is showing all the Category objects, and also serves to let us select a particular category. The bottom left grid is showing the children of the currently selected Category, and the bottom right grid is showing the contents of the currently selected Category’s Path association. Exactly what I needed.

Yes, the result is exactly the same as my convoluted code, and yes I had to learn a bit of OCL (this is the best OCL reference I’ve found so far, BTW. Thank you Anthony), but it just feels so much more ECO-like to be able to tell the framework what I want at a higher level, rather than having to explicitly say how to do it. Sure, I always want to have the option to take control over how things happen, but for stuff like this, I couldn’t care less.
<Sigh> Once again I’m reminded, ECO is love.
Oh, you can download the source for this example here (and yes, I realise I can’t spell, but then Delphi doesn’t spell check my Project names for me, so it’s not my fault).
Be the first to leave a comment. Don’t be shy.