Query Objects vs. Methods On The Repository
I am somewhere in the middle, since I am doing almost all queries directly on the repository, but I am passing it a query object. The main idea is that I don't really deal with the query object, it just happens behind the scenes:
One important case for query objects is when you have complex searching, as I said, Querying is a Business Concern. The traditional case is for a search screen, where you may have several dozens criteria (and I don't kid about the several dozens) that you need to search for. But there are many cases where in order to perform a business operation, you need to perform a non trivial query. Those are often dynamic queries, changing according to business logic and the state of the moon.
In those cases, I generally tend to separate those out into explicit query objects, using [UseCaseName]Finder, which can then be use:
CustomersInDebtFinder finder= new CustomersInDebtFinder( CurrentEmployee )
.DebtIsOverDueAt( AppContext.CurrentApplicationDate );
if(CurrentEmployee.IsManager && shouldShowSubordinateItems )
finder.FindCustomersWithDebtOverSubordinatesMaxDebt( CurrentEmployee );
The mechanics of the query is fairly complex, and a query object allows me to express them in a way that is much more intent revealing.