LinqSpecs; the why

I will show in this post the why of linqspecs.

As an example; lets imagine the domain of Chinook where you have Artists, Albums and Tracks. I will start with this simple View Model;

public class AlbumBrowserViewModel
{
    public Artist SelectedArtist { get; set; }
    
    public DateTime? ReleasedDateFrom { get; set; }
    public DateTime? ReleasedDateTo { get; set; }

    public void Filter()
    {
        CurrentAlbums = 
    }

    public IEnumerable<Album> CurrentAlbums { get; private set; }
}

Pay attention to the line 10, because now I will explain four different approaches to query the data, abstracting the data access code and the separation of concerns for this case.


Data Access Object pattern (without Expressions)

We are going to start a Data Access Object with the following interface:

public interface IAlbumDao
{
    IEnumerable<Album> GetAlbumByArtist(Artist artist);
    IEnumerable<Album> GetAlbumReleasedBetweenDates(DateTime? fromDate, DateTime? toDate);
    IEnumerable<Album> GetAlbumByArtistReleasedBetweenDates(Artist artist, DateTime? fromDate, DateTime? toDate);
}

So, now we can start writing the first test as follows:

public void can_filter_by_artist()
{
    var dao = new Mock<IAlbumDao>();
    var rollingStones = new Artist();
    var someAlbum = new Album();
    var albumList = new List<Album>{someAlbum};

    dao.Setup(d => d.GetAlbumByArtist(rollingStones))
        .Returns(albumList);

    var browser = new AlbumBrowserViewModel(dao.Object);
    
    browser.SelectedArtist = rollingStones;
    browser.ReleasedDateFrom = null;
    browser.ReleasedDateTo = null;

    browser.Filter();

    browser.CurrentAlbums
        .Should().Have.SameValuesAs(albumList);
}

Injecting the dao in the view model, the implementation, so far is:

public void Filter()
{
    CurrentAlbums = albumDao.GetAlbumByArtist(SelectedArtist);
}
but in the end it will looks like:
public void Filter()
{
    if(SelectedArtist != null 
    && (ReleasedDateFrom == null || ReleasedDateTo == null))
    {
        CurrentAlbums = albumDao.GetAlbumByArtist(SelectedArtist);
        return;
    }
    if(SelectedArtist == null 
    && (ReleasedDateFrom != null || ReleasedDateTo != null))
    {
        CurrentAlbums = albumDao
                .GetAlbumReleasedBetweenDates(ReleasedDateFrom, ReleasedDateTo);
        return;
    }
    if(SelectedArtist != null 
    && (ReleasedDateFrom != null || ReleasedDateTo != null))
    {
        CurrentAlbums = albumDao
                .GetAlbumByArtistReleasedBetweenDates(ReleasedDateFrom, ReleasedDateTo);
        return;
    }
    CurrentAlbums = albumDao.GetAllAlbums(); //What?
}

As you can see our Dao needs three different methods for these queries, although you can call the GetAlbumByArtistReleasedBetweenDates method always (sometimes with null parameters) but still suffer from a severe symptom: this is not flexible. On the other hand it violates the SOLID principles, because often you will need to touch the IDao and Dao. So forget about the Open Closed principle.

Pros:
  • Easy to test.
  • You can use the full feature set of the ORM inside the method.
Cons:
  • Violates OCP.
  • You could end with DAOs with 30 query methods inside.

Data Access Object pattern (with Expressions)

Now, I will talk about this interface:

public interface IDao<T>
{
    IEnumerable<T> Retrieve(Expression<Func<T, bool>> predicate);
}

This Data Access Object is much better than the former, but yet still have an issue. This IDao is hard, and almost impossible to mock. The main problem is that you can’t easily compare expressions. So, in my personal experience i know two ways of mocking it:

  • Compile the expression and assert the return value for some inputs.
  • Use a DaoStub with an in-memory collection inside.

I am not going to talk about the former, because I’ve a post about the subject.

The second is easy to understand, reading this test:

public void can_filter_by_artist()
{
    var rollingStones = new Artist();
    var someGirls = new Album {Artist = rollingStones};
    var daoStub = new DaoStub<Album>()
                    .Insert(someGirls, new Album());
    
    var browser = new AlbumBrowserViewModel(daoStub);
    
    browser.SelectedArtist = rollingStones;
    browser.ReleasedDateFrom = null;
    browser.ReleasedDateTo = null;

    browser.Filter();

    browser.CurrentAlbums
        .Should().Contain(someGirls)
                 .And.Have.Count.EqualTo(1);
}

The DaoStub<T>:
public class DaoStub<T> : IDao<T>
{
    private readonly ICollection<T> repository = new List<T>();

    public IDao<T> Insert(params T[] someGirls)
    {
        someGirls.ToList().ForEach(repository.Add);
        return this;
    }

    public IEnumerable<T> Retrieve(Expression<Func<T, bool>> predicate)
    {
        return repository.Where(predicate.Compile());
    }
}

and the implementation to pass the first test:

public class AlbumBrowserViewModel
{
    private readonly IDao<Album> albumDao;

    public AlbumBrowserViewModel(IDao<Album> albumDao)
    {
        this.albumDao = albumDao;
    }

    public Artist SelectedArtist { get; set; }
    
    public DateTime? ReleasedDateFrom { get; set; }
    public DateTime? ReleasedDateTo { get; set; }

    public void Filter()
    {
        CurrentAlbums = albumDao
            .Retrieve(a => a.Artist == SelectedArtist);
    }

    public IEnumerable<Album> CurrentAlbums { get; private set; }
}

I like this approach, however the two methods has a conceptual issue, you are “testing” a query that will be never executed. The linq provider for objects may work different than the Entity framework linq provider, or the NHibernate provider. So, you need to test the queries against the database provider, and if is possible I will highly recommend to test against the real world database. To summarize

Pros:

  • Very flexible and powerful.
  • Doesn’t violate OCP.

Cons:

  • It is hard to test and mock.
  • If you don’t use carefully you can end with a lot of predicates all over the code.

Query object pattern (or my style of query object pattern)

Forget about the dao, and start thinking in the following interface:

public interface IAlbumBrowseQuery
{
    Artist SelectedArtist { get; set; }
    DateTime? ReleasedDateFrom { get; set; }
    DateTime? ReleasedDateTo { get; set; }

    IEnumerable<Album> Execute();
}

For this case, you will only have to map, the UI fields to the query properties, but believe me there are few cases like this. I have named the query like the use case on purpose, because for this case I don’t want anybody modifying this interface unless is required for the use case.

The test and implementation are very simple, and you can mock this interface as we have mocked the first IDao. So, you can test your ViewModel.

Pros:

  • If you give to the query an specific responsibility, this pattern does not violate the OCP principle.
  • You can use the full featured set of the ORM tool, for instance, you can write your queries even in hql but for this case I will highly recommend you the Criteria API. This is not so important when you are using EF because linq is the only way you can write queries.

Cons:

  • You have to write an interface and the implementation per each query.
  • This pattern is less flexible than using dao with expression, if you only use this pattern you can end with a lot of query objects.

LinqSpecs; my baby project

I will use a DAO interface like this:

public interface IDao<T>
{
    IEnumerable<T> Retrieve(Specification<T> specification);
}

And I’ve two specs like this:

public class ByArtistSpecification : Specification<Album>
{
    public ByArtistSpecification(Artist artist)
    {
        Artist = artist;
    }

    public Artist Artist { get; private set; }

    public override Expression<Func<Album, bool>> IsSatisfiedBy()
    {
        return a => a.Artist == Artist;
    }

    protected override object[] Parameters { get { return new[]{ Artist }; } }
}

You don’t need to mock this class in order to test your ViewModel. Lets add a test for this VM:

public void can_filter_by_artist()
{
    var rollingStones = new Artist();
    var someGirls = new Album ();
    var dao = new Mock<IDao<Album>>();


    dao.Setup(d => d.Retrieve(new ByArtistSpecification(rollingStones)))
        .Returns(new List<Album>{someGirls});

    var browser = new AlbumBrowserViewModel(dao.Object);
    
    browser.SelectedArtist = rollingStones;
    browser.ReleasedDateFrom = null;
    browser.ReleasedDateTo = null;

    browser.Filter();

    browser.CurrentAlbums
        .Should().Contain(someGirls);
}

It doesn't matter that you have two instances of ByArtistSpecification, they are equals if they share the same parameters (last method in the specification.

In fact I can write a setup like this:

dao.Setup(d => d.Retrieve(new ByArtistSpecification(rollingStones) &
                          new ByReleasedDateRangeSpecification(new DateTime(1984, 1, 1), 
                                                               new DateTime(1989, 1, 1))))
    .Returns(new List<Album>{someGirls});

 

Pros:

  • You write tests for what you should test
  • It is very flexible and powerful
  • You write less than with query objects
  • You can operate specifications &, | and ! are supported.
  • You can easily test the specifications targeting against the real provider.
  • Specifications are cheaper, you can even serialize them-

Cons:

  • Only works for linq, so you can access the full feature set of your ORM.
  • You need to write specifications (yet another artifact) :)

It goes without saying that the specification pattern is not a silver bullet, so you should choose the best pattern to meet your needs.

 

Thank you all! and I’m waiting for your comments.


blog comments powered by Disqus
  • Categories

  • Archives