Query Objects vs. DSL


 Most O/R Mappers today support some sort of Query Objects.
Query Objects are often some sort of semi fluent combination of objects and methods where you can build a query.
Query objects also seem to be the preferred way to build queries in code because they are “Typed”.
Being “Typed” comes with two major benefits, you get intellisense (to some extent) and you get compiler warnings if you do something way too funky with your query.
When Mats Helander started to build NPersist, he went for a DSL approach instead of QO’s and invented NPath which object query language similar to SQL in syntax.
So why go for an untyped DSL instead of typed QO?
Well, one thing that QO’s does not do is to verify your logic, you need unit tests for that.
And once you’ve got unit tests, the benefit of being strictly typed is reduced because with unit tests you can clearly see if your untyped code does work or not.
QO’s still got the benefit of intellisense,
But let’s look at the readability of two queries:
(the queries come from : http://www.mygenerationsoftware.com/phpbb2/viewtopic.php?t=107)

SELECT * FROM Employees 
( City LIKE 'Ind%' OR HireDate BETWEEN '1/1/95' AND '4/4/04' )

[edit: added npath sample]


SELECT * FROM Employee 
WHERE LastName LIKE 'A%' AND LastName != NULL OR 
( City LIKE 'Ind%' OR HireDate BETWEEN #1/1/95# AND #4/4/04# )

NOTE: npath specifies classes and properties , not tables and fields
See: *** Missing Page *** : Old blog is gone

dOOdas ORM:

Dim emps As Employees = New Employees 
emps.Where.LastName.Value = "A%" 
emps.Where.LastName.Operator = WhereParameter.Operand.Like 
Dim wp As WhereParameter = emps.Where.TearOff.LastName 
wp.Operator = WhereParameter.Operand.IsNotNull 
emps.Query.AddConjunction WhereParameter.Conj.Or 
emps.Where.City.Conjuction = WhereParameter.Conj.And 
emps.Where.City.Value = "Ind%" 
emps.Where.City.Operator = WhereParameter.Operand.Like 
emps.Where.HireDate.Conjuction = WhereParameter.Conj.Or 
emps.Where.HireDate.Operator = WhereParameter.Operand.Between 
emps.Where.HireDate.BetweenBeginValue = "1/1/95" 
emps.Where.HireDate.BetweenEndValue = "4/4/04" 

Are QO’s really sane?
If the whole purpose of an O/R Mapper is to reduce code and enable RAD, shouldn’t it be easier to query your DB?
I was a LLBL gen pro user a few years ago and loved most parts of it, but I just couldn’t stand the QO’s.
Just making a query with a few conditions and some sorting would generate queries similar to the one above.
Even if Frans has excellent documentation and the classes got intellisense and all, I still had to spend way too much time
just to make a simple query that should take a few seconds to write.
(I have to add that I haven’t looked at LLBL Gen since and Frans might have altered the API or added some DSL, I’m just stating what I experienced with it about 2 years ago.
my arguments are also targeted against QO’s in general, not only the ones in LLBL Gen)

Later on I got in contact with Mats and saw NPath for the first time, and I loved it, NPath is the #1 reason I teamed up with Mats and started co-develop NPersist.
With NPath I can write queries that are similar to SQL but instead of targeting your DB schema you target your domain classes and properties, and instead of creating joins you just traverse property paths.

So even if NPath is untyped I still find it way more productive than any QO’s and I get a smaller code base which is easy to read and since I do unit tests I can verify that my untyped queries does work as intended.
It would be very interesting to hear other opinions on this topic and why QO’s still is the most common way to make queries in O/R Mappers?
Is it because of the intellisense?
or because most people don’t do unit tests?
or just because it looks cool with some huge object graph?
or because most O/R vendors don’t know how to make a decent parser?

Fire away! :-)

Just added this sample incase anyone is interested in NPath and in mem querying:

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s