1

I was looking to an alternative to Repository Pattern and I've read about "Query object pattern" (http://lostechies.com/jimmybogard/2012/10/08/favor-query-objects-over-repositories/). However the implementation provided in the link above is not exactly what I was looking for - I look for something that can be easily injected, easily tested and easily extended/changed (only last point holds in the link-implementation). I thought a bit and I think "I have invented" solution. Suppose I have controller BlogEntriesController (i'm talking about mvc asp application with ORM) and I inject to constructor class:

public class BlogEntriesQueries
{
    IRetrieveQuery<BlogEntryEntity> PageBlogEntries { get; set; }
    IRetrieveQuery<BlogEntryEntity> ProposedBlogEntries { get; set; }
    IAddQuery<BlogEntryEntity> CreateNewBlogEntry { get; set; }
    ... etc..
}

where IRetrieveQuery<T> is smth like:

public interface IRetrieveQuery<TEntity> where TEntity : EntityBase
     IQueryable<TEntity> CurrentQuery { get; }
     IRetrieveQuery<TEntity> InvokeQuery(IRetrieveQuery<TEntity> subQuery);
     IEnumerable<TEntity> GetQueryResults();
}

Then all the work I'd have to do is proper configuration of IoC container to inject queries into controller and proper calls in controller like: _blogQueries.ProposedBlogEntries.GetQueryResults() The question is - it is good solution - are there any drawbacks that I don't see? I think i'd get testability (don't even have to mock ISession in case of NHibernate) and it'd be easily extensible but I'm not an expert (especially at database applications) by any means.

3

Query testing can be handled easily without need to mock them. You just need to approach it from slightly different view. Example is here.

Second thing is: Do you really need ability to inject queries? Queries are usually closely tied to business logic they are used to. Are you really going to gain something by complicating your life by abstracting away each query? Every time you create some design, make sure you actually write significant amount of code, which uses this design, so you can evaluate how complex it is to actually use the design.

Final practical note : Are you sure your queries always work on single entity? Or return said entity? Queries are usually quite complex. You can just use LINQ directly if you don't need complex queries.

One more thing I noticed : Are you reusing single query across all calls? Is that really a query? Looks like different form of repository. How are you going to pass parameters for query?

2
  • Is mocking ISession with sqlite, using linq for simple queries - for complex one creating query class (and don't necessarily abstract it) ok then?
    – fex
    Aug 10 '14 at 9:28
  • @fex I don't really have experience mocking ISession, but from what I read, using SQLite or in-memory implementation should work fine. The reason why people suggest mocking repository is because their favorite ORM (or pure SQL calls) don't support direct mocking. Which is not case with NHibernate.
    – Euphoric
    Aug 10 '14 at 9:36
2

I think you might like the query object pattern I wrote for NHibernate:https://github.com/shaynevanasperen/NHibernate.Sessions.Operations

It makes it easy to build and consume your own query objects, with support for "3rd level" caching and query-result transformation. It provides an IDatabases interface, which you use to invoke queries and commands. If you derive your query and command objects from the provided base classes, you can then mock calls to the IDatabases interface in your unit tests.

It works by using an interface like this:

public interface IDatabases
{
    ISessionManager SessionManager { get; }

    T Query<T>(IDatabaseQuery<T> query);
    T Query<T>(ICachedDatabaseQuery<T> query);

    void Command(IDatabaseCommand command);
    T Command<T>(IDatabaseCommand<T> command);
}

Given a POCO entity class like this:

class Database1Poco
{
    public int Property1 { get; set; }
    public string Property2 { get; set; }
}

You can build query objects like this:

class Database1PocoByProperty1 : DatabaseQuery<Database1Poco>
{
    public override Database1Poco Execute(ISessionManager sessionManager)
    {
        return sessionManager.Session.Query<Database1Poco>().SingleOrDefault(x => x.Property1 == Property1);
    }

    public int Property1 { get; set; }
}

And then use them like this:

var database1Poco = _databases.Query(new Database1PocoByProperty1 { Property1 = 1 });
2
  • How to not be a spammer
    – gnat
    Aug 13 '15 at 20:30
  • 1
    My apologies, I was in a hurry. I've updated to answer to be less spammy now
    – Shayne
    Aug 14 '15 at 0:16
1

This is a correct implementation , you are going in right direction and will have no side effects. You might want to write create a integration test to ensure that query api is designed as per you need.

Keep it simple as much you can. Dont bloat it with pattern util you need one.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.