I have picked up a project that uses the specification pattern, a pattern I have not used before, and I had to go and research the pattern. I have noticed it doesn't have OrderBy and Skip/Take functionality, and I can't find anywhere that shows how to implement this with the pattern.
I am struggling to think of how best to add this to the specification pattern. But I have hit issues, like the specification deals with "Expression<Func<T, bool>>
" whereas I don't think I can store this along with orderby's etc
Basically there is a class like this:
public class Specification<T> : ISpecification<T>
{
public Expression<Func<T, bool>> Predicate { get; protected set; }
public Specification(Expression<Func<T, bool>> predicate)
{
Predicate = predicate;
}
public Specification<T> And(Specification<T> specification)
{
return new Specification<T>(this.Predicate.And(specification.Predicate));
}
public Specification<T> And(Expression<Func<T, bool>> predicate)
{
return new Specification<T>(this.Predicate.And(predicate));
}
public Specification<T> Or(Specification<T> specification)
{
return new Specification<T>(this.Predicate.Or(specification.Predicate));
}
public Specification<T> Or(Expression<Func<T, bool>> predicate)
{
return new Specification<T>(this.Predicate.Or(predicate));
}
public T SatisfyingItemFrom(IQueryable<T> query)
{
return query.Where(Predicate).SingleOrDefault();
}
public IQueryable<T> SatisfyingItemsFrom(IQueryable<T> query)
{
return query.Where(Predicate);
}
}
This allows to create a specification, passing in a where clause. It also allows chaining of rules with the "And", "Or". For example:
var spec = new Specification<Wave>(w => w.Id == "1").And(w => w.WaveStartSentOn > DateTime.Now);
How can I add a method for "OrderBy" and "Take"?
As this is existing code, I can't do any changes that would affect existing code, and it would be quite a job to refactor it. So any solution would need to play nicely with what is there.