Wednesday, 19 November 2008

HQL-lo World

I've been playing with Castle ActiveRecord for a project I'm working on, and hit a brick wall earlier tonight that left me completely stuck for a couple of hours... and turned out to be incredibly simple and obvious. Turns out I'd refactored one of my business objects - from Page to CmsPage - and hadn't noticed that in one particular place in the code, I was doing this:

var rootPages = new SimpleQuery<CmsPage>(@"from Page p where p.Parent is null");
return (rootPages.Execute());

The Execute() call there was throwing an ActiveRecordException that just said {"Could not perform ExecuteQuery for CmsPage"} - no InnerException, nothing showing up in SQL Profiler, nothing except a bunch of query strings that all looked fine to me:

image

Even enabling ActiveRecord logging (which was wonderfully easy, by the way) didn't help - I couldn't see anything obviously amiss in the NHibernate logs.

Turns out I'd not yet got my head around a fundamental concept of object-relational mapping, namely that you are querying your objects, not your database. The string literal in the SimpleQuery definition that looks a bit like LINQ is HQL - Hibernate Query Language. I'd used the [ActiveRecord(Table="Page")] attribute to map the renamed class to the underlying DB table, which is still called Page, and it just completely didn't occur to me that the HQL query needs to be changed to reflect the new class name. Change that query to

var rootPages = new SimpleQuery<CmsPage>(@"from CmsPage p where p.Parent is null");

and it works as intended. I fear this ORM stuff is going to take some getting used to...

2 comments:

Mike Hadlow said...

Not so much an ORM question as a string literal one. Have you thought of trying LINQ to NHibernate instead of HQL? It's far from perfect, but is fine for most simple cases.

Dylan said...

I'm actually using Castle ActiveRecord for this - this is the first situation I've encountered where the abstraction over NHibernate has leaked and I've had to write HQL stuff directly. I'll check out the LINQ stuff, though - thanks!