As you can see from the previous post, there are 3 options to abstract away queries in a testable manner (and we will add one theoretical one for the Boo):
1. Put queries right into some domain-specific repository implementation (i.e.: CustomerRepository.FindImportantCustomers) and ask the container about it.
- Pro: Simple and looks as if there is no logical separation between the repository and queries
- Con: Low scalability
- Con: Coupled code that would take some effort to test
2. Put queries into the extensions that use Repository[T].Find method.
- Pro: A bit more abstraction and testability, than in the previous option
- Con: Does not make a lot of sense
3. Put queries into the separate classes - Specification/QueryFor approach.
- Con: adds complexity to the code
- Con: creating separate class per query will add quite some noise around the code and drop the maintainability
- Con: it is not possible to leverage "Repository.Find(string criteria)" method (it could be used for queries, that are not supported by ORM-specific Linq implementation)
- Pro: scalable and testable solution
- Pro: encoded logics is easy to reuse (i.e. adding "IsSatisfiedBy" to all specifications/queries as Nick suggests)
4. Use some query DSL
- Con: adds even more complexity (unless DSL is already used by the solution)
- Con: adds one more syntax to remember (C# + query DSL + Linq) and increases the barrier for introducing new .NET developers into the team
- Con: Boo does not support Linq, yet
- Pro: extremely low code noise
- Pro: extremely flexible, scalable and reusable solution
And additionally there is an option of abstracting the IRepository interface away from the ORM-specific implementation. It helps with unit testing and theoretically prepares us for the possible ORM switch down the development road (if you are seriously considering the last factor then you are either framework developer, member of the research team or have made wrong development decision some time ago).
As you can see, we have quite a number of combinations here (although, I'm sure, there are more) for a single concept of separating Linq queries (with all the business logic) away from the IRepository code. Picking the one, that is the most efficient for your solution, would require considering even larger amount of factors: starting from the skill level of the development resources and up to long-term requirements for the entire solution.
That's what makes software development so interesting, after all.
In the next post within the XPO+ORM+IOC series I'll address the problem of efficient exception handling, when you have IoC and IRepository at hand.